public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/glibc] rawhide: Auto-sync with upstream branch master
@ 2026-09-24 11:48 
  0 siblings, 0 replies; 7+ messages in thread
From:  @ 2026-09-24 11:48 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/glibc
            Branch : rawhide
            Commit : 52b122b0e8f460dc6c7fce7959d4bdc24f674588
            Author : Frédéric Bérat <fberat@redhat.com>
            Date   : 2026-09-24T11:10:23+02:00
            Stats  : +116/-10817 in 4 file(s)
            URL    : https://src.fedoraproject.org/rpms/glibc/c/52b122b0e8f460dc6c7fce7959d4bdc24f674588?branch=rawhide

            Log:
            Auto-sync with upstream branch master

Upstream commit: 04a3995650ec181e98b768fef59f1ad228a87be5

- advisories: fix tag for CVE in SA-2026-0023 (Rolf Eike Beer)
- Update CVSSv3.1 score for GLIBC-SA-2026-0022 (Carlos O'Donell)
- Publish CVE-2026-95818 advisory (Carlos O'Donell)
- Publish CVE-2026-86805 advisory (Carlos O'Donell)
- elf: Fix ld.so SIGSEGV in trace mode with unresolved TLS symbols (BZ 34532) (Adhemerval Zanella)
- nptl: Retry SIGSETXID delivery on EAGAIN in setxid (bug 21108) (Adhemerval Zanella)
- math: Sync tgamma with CORE-MATH (Adhemerval Zanella)
- math: Sync exp10m1f with CORE-MATH (Adhemerval Zanella)
- math: Sync acosf with CORE-MATH (Adhemerval Zanella)
- math: Sync lgamma with CORE-MATH (Adhemerval Zanella)
- Fix d_t_fmt and date_fmt in en_SE [BZ #34635] (Mike FABIAN)
- stdlib: Don't call clearenv from __libc_setenv_freemem (Mark Wielaard)
- Publish CVE-2026-8674 advisory (Adhemerval Zanella)
- malloc: Improve calloc [BZ #34582] (Wilco Dijkstra)
- x86-64: Link tst-shstk-legacy-1{f,g} with -Wl,--no-as-needed (H.J. Lu)
- Revert "linux: Add __libc_procmaps_iterate" (Adhemerval Zanella)
- Revert "linux: Use __libc_procmaps_iterate on __readonly_area_fallback" (Adhemerval Zanella)
- Revert "nptl: Use __libc_procmaps_iterate on pthread_getattr_np" (Adhemerval Zanella)
- Revert "nptl: Fall back to AT_EXECFN on __pthread_main_stack without /proc" (Adhemerval Zanella)
- Revert "nptl: Account for the stack guard gap on pthread_getattr_np (BZ 34637)" (Adhemerval Zanella)
- Mark swapcontext returns_twice by default [BZ #23130] (Stian Halseth)
- libio: validate the wide vtable via a bounds-checked index (Alessandro Schino)
- resolv: Fix assertion failure on search list truncation [BZ 31026, CVE-2026-8674] (Adhemerval Zanella)
- nptl: Account for the stack guard gap on pthread_getattr_np (BZ 34637) (Adhemerval Zanella)
- nptl: Fall back to AT_EXECFN on __pthread_main_stack without /proc (Adhemerval Zanella)
- nptl: Use __libc_procmaps_iterate on pthread_getattr_np (Adhemerval Zanella)
- linux: Use __libc_procmaps_iterate on __readonly_area_fallback (Adhemerval Zanella)
- linux: Add __libc_procmaps_iterate (Adhemerval Zanella)
- linux: Add buffer argument and line truncation to __libc_procutils_read_file (Adhemerval Zanella)
- Publish CVE-2026-80489 advisory (Carlos O'Donell)
- Publish CVE-2026-77117 advisory (Carlos O'Donell)
- Publish CVE-2026-19542 advisory (Adhemerval Zanella)
- Publish CVE-2026-19499 advisory (Adhemerval Zanella)
- math: Update tanh from CORE-MATH (revision dbd377a9) (Adhemerval Zanella)
- io: Reject an empty path list on fts_open [BZ #25434] [BZ #34610] (Adhemerval Zanella)
- malloc: Reject the top chunk in mem2chunk_check (Magnus Lindholm)
- aarch64: Add MTE mode tunable (Yury Khrustalev)
- elf: Do not load cache extensions from an old-format ld.so.cache [BZ #34600] (Shamil Abdulaev)
- Publish CVE-2026-89092 advisory (Siddhesh Poyarekar)
- x86: Set AVX10 active only if XMM/YMM/ZMM are supported (H.J. Lu)
- time: handle ^ and # modifiers with %Z in wcsftime (bug 34611) (Andreas Schwab)
- x86: Detect APX_NCI_NDD_NF (H.J. Lu)
- math: let architectures signal underflow after narrowing (Matt Turner)
- locale: fix memory leaks in write_locales and write_charmaps (Ruslan Valiyev)
- math: Set errno to ERANGE for logb (+-0) [BZ #6793] (Shamil Abdulaev)
- alpha: Use a comdat group for the shared divide-by-zero handler [BZ #20543] (Matt Turner)
- nptl: Skip pretty-printer tests without python3 [BZ #34507] (Hemanth Kumar M D)
- Record CVE-2026-18374 fix (Florian Weimer)
- libio: Add test for fopen with an empty ", ccs=" value [BZ #34574] (Shamil Abdulaev)
- libio: Fix CVE-2026-18374 heap buffer overflow in ccs= handling (Dongkyun Son)
- getrusage: Add smoke test for getrusage (Ondrej Marek)
- powerpc: Restore NULL check on _rtld_global_ro in INIT_ARCH [BZ #34503] (Michael Pfeifroth)
- stdio-common: Skip the a and A conversions for the IBM extended format (Matt Turner)
- stdio-common: Handle subnormal values in the printf format tests (Matt Turner)
- stdio-common: Add printf format tests for the a and A conversions (Matt Turner)
- stdio-common: Add printf format tests for the b and B conversions (Matt Turner)
- stdio-common: Verify printf format tests with Python rather than AWK (Matt Turner)
- hurd: Make __file_name_lookup_at apply upmask for O_TMPFILE (BZ 34493) (Samuel Thibault)
- hurd: Make readlinkat check bogus length returned by translator (BZ 34504) (Samuel Thibault)
- hurd: Fix setreuid/setregid setting saved ID to new effective ID (BZ 34505) (Samuel Thibault)
- stdlib, wcsmbs: Add missing __nonnull to strto*/wcsto* [BZ #33053] (Shamil Abdulaev)
- elf: Open the normalized $ORIGIN rpath in AT_SECURE programs (BZ 34360) (Adhemerval Zanella)
- test: Fix tst-personality (Yury Khrustalev)
- manual: adjust reference to man-pages following proc(5) split-up (Collin Funk)
- Updates udp.h from Linux 6.19 to netinet/udp.h (Jiayuan Chen)
- nptl: Test case for bug 34546 (Florian Weimer)
- nptl: Use FAIL_UNSUPPORTED in init_tpp_test in tst-tpp.h (Florian Weimer)
- nptl: Revert TPP updates on pthread_mutex_*lock failure (bug 34546) (Florian Weimer)
- nptl: Fix test error reporting in CHECK_TPP_PRIORITY in tst-tpp.h (Florian Weimer)
- nptl: Revert robust list head on pthread_mutex_timedlock failure (bug 34542) (Florian Weimer)
- nptl: Treat negative times as timed out in PI futex locking (bug 34543) (Florian Weimer)
- stdio-common: Keep trailing zeros where %#g rounds into a new decade (BZ 34578) (Matt Turner)
- stdio-common: Iterate over the huge width for one printf function only (Matt Turner)
- elf: Remove dead l_need_tls_init static-TLS init path (Adhemerval Zanella)
- elf: Remove __chk_fail from dl-minimal.c (Adhemerval Zanella)
- elf: Allow RPATH/RUNPATH for static-pie (BZ 33326) (Adhemerval Zanella)
- Fix assert during static startup (BZ 33326) (Adhemerval Zanella)
- Use _dl_writev on __libc_message_impl (Adhemerval Zanella)
- nptl: Add __raise_direct (Adhemerval Zanella)
- tst-backtrace5: split long line (Samuel Thibault)
- tst-backtrace5: Fix on hurd (Samuel Thibault)
- fcntl: drop nonnull attribute for openat, openat2's path argument [BZ #34313] (Sam James)
- io: drop nonnull attribute for fchmodat, faccessat, fchownat's path argument [BZ #34313] (Sam James)
- hurd: Move SINGLE_THREAD_P / RTLD_SINGLE_THREAD_P to single-thread.h (Samuel Thibault)
- stdlib: merge some tests from gnulib (Collin Funk)
- nptl: Propagate EDEADLK from FUTEX_LOCK_PI for errror-checking mutexes (Moritz Klammler)
- advisories: fix typo in README (Rolf Eike Beer)
- Use __attribute_optimization_barrier__ for the remaining noclone users (Matt Turner)
- io: Do not alias fts and fts64 when inode types differ (Magnus Lindholm)
- Use FAIL_UNSUPPORTED more (Sam James)
- iconvdata: Test case for bug 34556, bug 34568 (Florian Weimer)
- iconvdata: EUC_JISX0213 decoding lacks pending character reset (CVE-2026-80489) (Florian Weimer)
- iconvdata: SHIFT_JISX0213 decoding lacks pending character reset (CVE-2026-77117) (Florian Weimer)
- localedata: bn_BD, bn_IN: use full Gregorian month names for abmon (Azharul Haque)
- manual: Fix some typos in the Low-Level Input/Output chapter (Collin Funk)
- x86: Update AVX10 support (H.J. Lu)
- Document CVE-2026-18374 and new CVSS tag (Siddhesh Poyarekar)
- aarch64: Add memory clobber to pkey_write (Yury Khrustalev)
- stdlib: Fix right-justification in strfmon (bug 34510, CVE-2026-19499) (Florian Weimer)
- hurd: Set _TIME_BITS=32 for installed programs on i386/Hurd (Samuel Thibault)
- Add check-symbol-version.awk (H.J. Lu)
- LoongArch: Add standard search paths for 32-bit (mengqinggang)
- LoongArch: Support pointer guard on LoongArch32 (mengqinggang)
- hurd: Warn about setting _TIME_BITS=64 on i386 GNU Hurd (Samuel Thibault)
- math: Update tanh from CORE-MATH (revision bb39e4fa) (Adhemerval Zanella)
- tests: elf: Fix flaky thp tests (Yury Khrustalev)

Remove patches already applied upstream:
- glibc-rh2457183-1.patch
- glibc-rh2457183-2.patch

---
diff --git a/glibc-rh2457183-1.patch b/glibc-rh2457183-1.patch
deleted file mode 100644
index aa38d71..0000000
--- a/glibc-rh2457183-1.patch
+++ /dev/null
@@ -1,4590 +0,0 @@
-Revert "io: Consolidate fts implementation"
-
-This reverts commit b9a2dea54abd1c5db9773a92c97dd3202bbaec62.
-
-Reason for revert: This change breaks dracut due to the way it uses
-fts: <https://bugzilla.redhat.com/show_bug.cgi?id=2457183>
-
-diff --git a/SHARED-FILES b/SHARED-FILES
-index 645040d7e10c1927..126aaf096d93371c 100644
---- a/SHARED-FILES
-+++ b/SHARED-FILES
-@@ -49,7 +49,7 @@ gnulib:
-   io/cycle-check.h
-   io/dev-ino.h
-   io/fts-cycle.c
--  io/fts-common.c
-+  io/fts.c
-   io/i-ring.c
-   io/same-inode.h
-   locale/programs/3level.h
-diff --git a/io/fts-common.c b/io/fts-common.c
-deleted file mode 100644
-index 3825f0aeb4eb1594..0000000000000000
---- a/io/fts-common.c
-+++ /dev/null
-@@ -1,2208 +0,0 @@
--/* Traverse a file hierarchy.
--
--   Copyright (C) 2004-2026 Free Software Foundation, Inc.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--/*-
-- * Copyright (c) 1990, 1993, 1994
-- *      The Regents of the University of California.  All rights reserved.
-- *
-- * Redistribution and use in source and binary forms, with or without
-- * modification, are permitted provided that the following conditions
-- * are met:
-- * 1. Redistributions of source code must retain the above copyright
-- *    notice, this list of conditions and the following disclaimer.
-- * 2. Redistributions in binary form must reproduce the above copyright
-- *    notice, this list of conditions and the following disclaimer in the
-- *    documentation and/or other materials provided with the distribution.
-- * 4. Neither the name of the University nor the names of its contributors
-- *    may be used to endorse or promote products derived from this software
-- *    without specific prior written permission.
-- *
-- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
-- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-- * SUCH DAMAGE.
-- */
--
--#include <config.h>
--
--#if defined LIBC_SCCS && !defined GCC_LINT && !defined lint
--static char sccsid[] = "@(#)fts.c       8.6 (Berkeley) 8/14/94";
--#endif
--
--#if _LIBC
--# include <fts.h>
--#else
--# include "fts_.h"
--#endif
--#if _LIBC || HAVE_SYS_PARAM_H
--# include <sys/param.h>
--#endif
--#include <sys/stat.h>
--#include <fcntl.h>
--#include <errno.h>
--#include <stddef.h>
--#include <stdint.h>
--#include <stdlib.h>
--#include <string.h>
--#include <unistd.h>
--
--/* Support for the LFS API version.  */
--#ifndef FTS_OPEN
--# define FTS_OPEN fts_open
--# define FTS_CLOSE fts_close
--# define FTS_READ fts_read
--# define FTS_SET fts_set
--# define FTS_CHILDREN fts_children
--# define FTSOBJ FTS
--# define FTSENTRY FTSENT
--# define INO_T ino_t
--# define STRUCT_STAT stat
--# define FSTAT __fstat
--# define FSTATAT __fstatat
--# define STRUCT_STATFS statfs
--# define FSTATFS __fstatfs
--#endif
--
--#if ! _LIBC
--# include "attribute.h"
--# include "fcntl--.h"
--# include "openat.h"
--# include "opendirat.h"
--# include "same-inode.h"
--# define OPENDIRAT opendirat
--# define FTSENT_WRAPPER(__p) __p
--# define FTS_COMPAR_CAST(__fn) __fn
--#else
--# include <stdbool.h>
--
--# define internal_function
--# define FALLTHROUGH               ; [[fallthrough]]
--# define HAVE_STRUCT_DIRENT_D_TYPE 1
--# define GNULIB_FTS_DEBUG          0
--# ifdef O_PATH
--#  define O_SEARCH                 O_PATH
--# else
--#  define O_SEARCH                 O_RDONLY
--# endif
--# define HAVE_SYS_VFS_H            1
--# define HAVE_FSTATFS              1
--# define HAVE_STRUCT_STATFS_F_TYPE 1
--# define HAVE_OPENAT               1
--# define HAVE_WORKING_O_NOFOLLOW   1
--# define _GL_CMP(a, b)             ((a) < (b) ? -1 : (a) > (b))
--# define OPENDIRAT                 __opendirat
--
--static inline bool openat_needs_fchdir (void)
--{
--  return false;
--}
--
--static inline bool streq (const char *s1, const char *s2)
--{
--  return strcmp (s1, s2) == 0;
--}
--# define reallocarray              __libc_reallocarray
--# define fchdir                    __fchdir
--# define close                     __close
--# define closedir                  __closedir
--# define fcntl                     __fcntl
--# define readdir                   __readdir
--# ifndef dirfd
--#  define dirfd                    __dirfd
--# endif
--# define open                      __open
--# define openat                    __openat
--
--# include "cycle-check.c"
--# include "i-ring.c"
--
--struct FTSENT_wrapper
--{
--  FTSOBJ *fts_fts;                /* the file hierarchy itself */
--  DIR *fts_dirp;                  /* Dir pointer for any directory containing
--				     more entries than we read at one time.  */
--  struct STRUCT_STAT fts_stat;
--
--  FTSENTRY ent;
--};
--
--/* glibc historicaly defines the FTS::fts_compar as having 'void *', while the
--   fts_open has a function point using 'FTSENT **' as argument.  */
--# define FTS_COMPAR_CAST(__fn) ((int (*) (void const *, void const *))__fn)
--
--# define FTSENT_WRAPPER(p) \
--    ((struct FTSENT_wrapper *) ((char *)(p) - offsetof(struct FTSENT_wrapper, ent)))
--#endif
--#define FTSENT_FTS(p)   (FTSENT_WRAPPER(p)->fts_fts)
--#define FTSENT_DIRP(p)  (FTSENT_WRAPPER(p)->fts_dirp)
--
--#include "flexmember.h"
--
--#include <dirent.h>
--#ifndef _D_EXACT_NAMLEN
--# define _D_EXACT_NAMLEN(dirent) strlen ((dirent)->d_name)
--#endif
--
--#if HAVE_STRUCT_DIRENT_D_TYPE
--/* True if the type of the directory entry D is known.  */
--# define DT_IS_KNOWN(d) ((d)->d_type != DT_UNKNOWN)
--/* True if the type of the directory entry D must be T.  */
--# define DT_MUST_BE(d, t) ((d)->d_type == (t))
--# define D_TYPE(d) ((d)->d_type)
--#else
--# define DT_IS_KNOWN(d) false
--# define DT_MUST_BE(d, t) false
--# define D_TYPE(d) DT_UNKNOWN
--
--# undef DT_UNKNOWN
--# define DT_UNKNOWN 0
--
--/* Any nonzero values will do here, so long as they're distinct.
--   Undef any existing macros out of the way.  */
--# undef DT_BLK
--# undef DT_CHR
--# undef DT_DIR
--# undef DT_FIFO
--# undef DT_LNK
--# undef DT_REG
--# undef DT_SOCK
--# define DT_BLK 1
--# define DT_CHR 2
--# define DT_DIR 3
--# define DT_FIFO 4
--# define DT_LNK 5
--# define DT_REG 6
--# define DT_SOCK 7
--#endif
--
--#ifndef S_IFBLK
--# define S_IFBLK 0
--#endif
--#ifndef S_IFLNK
--# define S_IFLNK 0
--#endif
--#ifndef S_IFSOCK
--# define S_IFSOCK 0
--#endif
--
--enum
--{
--  NOT_AN_INODE_NUMBER = 0
--};
--
--#ifdef D_INO_IN_DIRENT
--# define D_INO(dp) (dp)->d_ino
--#else
--/* Some systems don't have inodes, so fake them to avoid lots of ifdefs.  */
--# define D_INO(dp) NOT_AN_INODE_NUMBER
--#endif
--
--/* If possible (see max_entries, below), read no more than this many directory
--   entries at a time.  Without this limit (i.e., when using non-NULL
--   fts_compar), processing a directory with 4,000,000 entries requires ~1GiB
--   of memory, and handling 64M entries would require 16GiB of memory.  */
--#ifndef FTS_MAX_READDIR_ENTRIES
--# define FTS_MAX_READDIR_ENTRIES 100000
--#endif
--
--/* If there are more than this many entries in a directory,
--   and the conditions mentioned below are satisfied, then sort
--   the entries on inode number before any further processing.  */
--#ifndef FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
--# define FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD 10000
--#endif
--
--enum
--{
--  _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD = FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
--};
--
--enum Fts_stat
--{
--  FTS_NO_STAT_REQUIRED = 1,
--  FTS_STAT_REQUIRED = 2
--};
--
--#ifndef __set_errno
--# define __set_errno(Val) errno = (Val)
--#endif
--
--/* If this host provides the openat function, then we can avoid
--   attempting to open "." in some initialization code below.  */
--#ifdef HAVE_OPENAT
--# define HAVE_OPENAT_SUPPORT 1
--#else
--# define HAVE_OPENAT_SUPPORT 0
--#endif
--
--#ifdef NDEBUG
--# define fts_assert(expr) ((void) (0 && (expr)))
--#else
--# define fts_assert(expr)       \
--    do                          \
--      {                         \
--        if (!(expr))            \
--          abort ();             \
--      }                         \
--    while (false)
--#endif
--
--static FTSENTRY  *fts_alloc (FTSOBJ *, const char *, size_t);
--static FTSENTRY  *fts_build (FTSOBJ *, int);
--static void      fts_lfree (FTSENTRY *);
--static void      fts_load (FTSOBJ *, FTSENTRY *);
--static size_t    fts_maxarglen (char * const *);
--static void      fts_padjust (FTSOBJ *, FTSENTRY *);
--static bool      fts_palloc (FTSOBJ *, size_t);
--static FTSENTRY  *fts_sort (FTSOBJ *, FTSENTRY *, size_t);
--static unsigned short int fts_stat (FTSOBJ *, FTSENTRY *, bool);
--static int      fts_safe_changedir (FTSOBJ *, FTSENTRY *, int, const char *);
--
--#include "fts-cycle.c"
--
--#ifndef MAX
--# define MAX(a,b) ((a) > (b) ? (a) : (b))
--#endif
--
--#ifndef SIZE_MAX
--# define SIZE_MAX ((size_t) -1)
--#endif
--
--#define ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
--
--#define CLR(opt)        (sp->fts_options &= ~(opt))
--#define ISSET(opt)      ((sp->fts_options & (opt)) != 0)
--#define SET(opt)        (sp->fts_options |= (opt))
--
--/* FIXME: FTS_NOCHDIR is now misnamed.
--   Call it FTS_USE_FULL_RELATIVE_FILE_NAMES instead. */
--#define FCHDIR(sp, fd)                                  \
--  (!ISSET(FTS_NOCHDIR) && (ISSET(FTS_CWDFD)             \
--                           ? (cwd_advance_fd ((sp), (fd), true), 0) \
--                           : fchdir (fd)))
--
--
--/* fts_build flags */
--/* FIXME: make this an enum */
--#define BCHILD          1               /* fts_children */
--#define BNAMES          2               /* fts_children, names only */
--#define BREAD           3               /* fts_read */
--
--#if GNULIB_FTS_DEBUG
--# include <inttypes.h>
--# include <stdio.h>
--bool fts_debug = false;
--# define Dprintf(x) do { if (fts_debug) printf x; } while (false)
--static void fd_ring_check (FTSOBJ const *);
--static void fd_ring_print (FTSOBJ const *, FILE *, char const *);
--#else
--# define Dprintf(x)
--# define fd_ring_check(x)
--# define fd_ring_print(a, b, c)
--#endif
--
--#define LEAVE_DIR(Fts, Ent, Tag)                                \
--  do                                                            \
--    {                                                           \
--      Dprintf (("  %s-leaving: %s\n", Tag, (Ent)->fts_path));   \
--      leave_dir (Fts, Ent);                                     \
--      fd_ring_check (Fts);                                      \
--    }                                                           \
--  while (false)
--
--static void
--fd_ring_clear (I_ring *fd_ring)
--{
--  while ( ! i_ring_empty (fd_ring))
--    {
--      int fd = i_ring_pop (fd_ring);
--      if (0 <= fd)
--        close (fd);
--    }
--}
--
--/* Overload the fts_statp->st_size member (otherwise unused, when
--   fts_info is FTS_NSOK) to indicate whether fts_read should stat
--   this entry or not.  */
--static void
--fts_set_stat_required (FTSENTRY *p, bool required)
--{
--  fts_assert (p->fts_info == FTS_NSOK);
--  p->fts_statp->st_size = (required
--                           ? FTS_STAT_REQUIRED
--                           : FTS_NO_STAT_REQUIRED);
--}
--
--/* Virtual fchdir.  Advance SP's working directory file descriptor,
--   SP->fts_cwd_fd, to FD, and push the previous value onto the fd_ring.
--   CHDIR_DOWN_ONE is true if FD corresponds to an entry in the directory
--   open on sp->fts_cwd_fd; i.e., to move the working directory one level
--   down.  */
--static void
--internal_function
--cwd_advance_fd (FTSOBJ *sp, int fd, bool chdir_down_one)
--{
--  int old = sp->fts_cwd_fd;
--  fts_assert (old != fd || old == AT_FDCWD);
--
--  if (chdir_down_one)
--    {
--      /* Push "old" onto the ring.
--         If the displaced file descriptor is non-negative, close it.  */
--      int prev_fd_in_slot = i_ring_push (&sp->fts_fd_ring, old);
--      fd_ring_print (sp, stderr, "post-push");
--      if (0 <= prev_fd_in_slot)
--        close (prev_fd_in_slot); /* ignore any close failure */
--    }
--  else if ( ! ISSET (FTS_NOCHDIR))
--    {
--      if (0 <= old)
--        close (old); /* ignore any close failure */
--    }
--
--  sp->fts_cwd_fd = fd;
--}
--
--/* Restore the initial, pre-traversal, "working directory".
--   In FTS_CWDFD mode, we merely call cwd_advance_fd, otherwise,
--   we may actually change the working directory.
--   Return 0 upon success. Upon failure, set errno and return nonzero.  */
--static int
--restore_initial_cwd (FTSOBJ *sp)
--{
--  int fail = FCHDIR (sp, ISSET (FTS_CWDFD) ? AT_FDCWD : sp->fts_rfd);
--  fd_ring_clear (&(sp->fts_fd_ring));
--  return fail;
--}
--
--/* Open the directory DIR if possible, and return a file
--   descriptor.  Return -1 and set errno on failure.  It doesn't matter
--   whether the file descriptor has read or write access.  */
--
--static int
--internal_function
--diropen (FTSOBJ const *sp, char const *dir)
--{
--  int open_flags = (O_SEARCH | O_CLOEXEC | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
--                    | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0));
--
--  int fd = (ISSET (FTS_CWDFD)
--            ? openat (sp->fts_cwd_fd, dir, open_flags)
--            : open (dir, open_flags));
--  return fd;
--}
--
--FTSOBJ *
--FTS_OPEN (char * const *argv,
--          register int options,
--          int (*compar) (const FTSENTRY **, const FTSENTRY **))
--{
--        /* Options check: glibc added other flags after FTS_NAMEONLY and
--	   FTS_STOP, and they are assumed to be private.  */
--        if (options & ~FTS_OPTIONMASK
--#if _LIBC
--	    || options & (FTS_NAMEONLY | FTS_STOP)
--#endif
--	    ) {
--                __set_errno (EINVAL);
--                return (NULL);
--        }
--        if ((options & FTS_NOCHDIR) && (options & FTS_CWDFD)) {
--                __set_errno (EINVAL);
--                return (NULL);
--        }
--#if !_LIBC
--        if ( ! (options & (FTS_LOGICAL | FTS_PHYSICAL))) {
--                __set_errno (EINVAL);
--                return (NULL);
--        }
--#else
--	/* glibc historically falls to FTS_PHYSICAL if no FTS_PHYSICAL or
--	   FTS_LOGICAL is specified.  */
--        if (! (options & (FTS_PHYSICAL | FTS_LOGICAL)))
--	  options |= FTS_PHYSICAL;
--#endif
--
--        /* Allocate/initialize the stream */
--        register FTSOBJ *sp = calloc (1, sizeof *sp);
--        if (sp == NULL)
--                return (NULL);
--        sp->fts_compar = FTS_COMPAR_CAST(compar);
--        sp->fts_options = options;
--
--        /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
--        if (ISSET(FTS_LOGICAL)) {
--                SET(FTS_NOCHDIR);
--                CLR(FTS_CWDFD);
--        }
--
--        /* Initialize fts_cwd_fd.  */
--        sp->fts_cwd_fd = AT_FDCWD;
--        if ( ISSET(FTS_CWDFD) && ! HAVE_OPENAT_SUPPORT)
--          {
--            /* While it isn't technically necessary to open "." this
--               early, doing it here saves us the trouble of ensuring
--               later (where it'd be messier) that "." can in fact
--               be opened.  If not, revert to FTS_NOCHDIR mode.  */
--            int fd = open (".", O_SEARCH | O_CLOEXEC);
--            if (fd < 0)
--              {
--                /* Even if "." is unreadable, don't revert to FTS_NOCHDIR mode
--                   on systems like Linux+PROC_FS, where our openat emulation
--                   is good enough.  Note: on a system that emulates
--                   openat via /proc, this technique can still fail, but
--                   only in extreme conditions, e.g., when the working
--                   directory cannot be saved (i.e. save_cwd fails) --
--                   and that happens on Linux only when "." is unreadable
--                   and the CWD would be longer than PATH_MAX.
--                   FIXME: once Linux kernel openat support is well established,
--                   replace the above open call and this entire if/else block
--                   with the body of the if-block below.  */
--                if ( openat_needs_fchdir ())
--                  {
--                    SET(FTS_NOCHDIR);
--                    CLR(FTS_CWDFD);
--                  }
--              }
--            else
--              {
--                close (fd);
--              }
--          }
--
--        /*
--         * Start out with 1K of file name space, and enough, in any case,
--         * to hold the user's file names.
--         */
--#ifndef MAXPATHLEN
--# define MAXPATHLEN 1024
--#endif
--        {
--          size_t maxarglen = fts_maxarglen(argv);
--          if (! fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
--                  goto mem1;
--        }
--
--        /* Allocate/initialize root's parent. */
--        FTSENTRY *parent = NULL;
--        if (*argv != NULL) {
--                if ((parent = fts_alloc(sp, "", 0)) == NULL)
--                        goto mem2;
--                parent->fts_level = FTS_ROOTPARENTLEVEL;
--          }
--
--        /* The classic fts implementation would call fts_stat with
--           a new entry for each iteration of the loop below.
--           If the comparison function is not specified or if the
--           FTS_DEFER_STAT option is in effect, don't stat any entry
--           in this loop.  This is an attempt to minimize the interval
--           between the initial stat/lstat/fstatat and the point at which
--           a directory argument is first opened.  This matters for any
--           directory command line argument that resides on a file system
--           without genuine i-nodes.  If you specify FTS_DEFER_STAT along
--           with a comparison function, that function must not access any
--           data via the fts_statp pointer.  */
--        bool defer_stat = (compar == NULL || ISSET(FTS_DEFER_STAT));
--
--        /* Allocate/initialize root(s). */
--        register FTSENTRY *root;
--        register size_t nitems;
--        FTSENTRY *tmp = NULL;     /* pacify gcc */
--        for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
--                /* *Do* allow zero-length file names. */
--                size_t len = strlen(*argv);
--
--                if ( ! (options & FTS_VERBATIM))
--                  {
--                    /* If there are two or more trailing slashes, trim all but one,
--                       but don't change "//" to "/", and do map "///" to "/".  */
--                    char const *v = *argv;
--                    if (2 < len && v[len - 1] == '/')
--                      while (1 < len && v[len - 2] == '/')
--                        --len;
--                  }
--
--                register FTSENTRY *p = fts_alloc(sp, *argv, len);
--                if (p == NULL)
--                        goto mem3;
--                p->fts_level = FTS_ROOTLEVEL;
--                p->fts_parent = parent;
--                p->fts_accpath = p->fts_name;
--                /* Even when defer_stat is true, be sure to stat the first
--                   command line argument, since fts_read (at least with
--                   FTS_XDEV) requires that.  */
--                if (defer_stat && root != NULL) {
--                        p->fts_info = FTS_NSOK;
--                        fts_set_stat_required(p, true);
--                } else {
--                        p->fts_info = fts_stat(sp, p, false);
--                }
--
--                /*
--                 * If comparison routine supplied, traverse in sorted
--                 * order; otherwise traverse in the order specified.
--                 */
--                if (compar) {
--                        p->fts_link = root;
--                        root = p;
--                } else {
--                        p->fts_link = NULL;
--                        if (root == NULL)
--                                tmp = root = p;
--                        else {
--                                tmp->fts_link = p;
--                                tmp = p;
--                        }
--                }
--        }
--        if (compar && nitems > 1)
--                root = fts_sort(sp, root, nitems);
--
--        /*
--         * Allocate a dummy pointer and make fts_read think that we've just
--         * finished the node before the root(s); set p->fts_info to FTS_INIT
--         * so that everything about the "current" node is ignored.
--         */
--        if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
--                goto mem3;
--        sp->fts_cur->fts_link = root;
--        sp->fts_cur->fts_info = FTS_INIT;
--        sp->fts_cur->fts_level = 1;
--        if (! setup_dir (sp))
--                goto mem3;
--
--        /*
--         * If using chdir(2), grab a file descriptor pointing to dot to ensure
--         * that we can get back here; this could be avoided for some file names,
--         * but almost certainly not worth the effort.  Slashes, symbolic links,
--         * and ".." are all fairly nasty problems.  Note, if we can't get the
--         * descriptor we run anyway, just more slowly.
--         */
--        if (!ISSET(FTS_NOCHDIR) && !ISSET(FTS_CWDFD)
--            && (sp->fts_rfd = diropen (sp, ".")) < 0)
--                SET(FTS_NOCHDIR);
--
--        i_ring_init (&sp->fts_fd_ring, -1);
--        return (sp);
--
--mem3:   fts_lfree(root);
--        free(FTSENT_WRAPPER(parent));
--mem2:   free(sp->fts_path);
--mem1:   free(sp);
--        return (NULL);
--}
--
--static void
--internal_function
--fts_load (FTSOBJ *sp, register FTSENTRY *p)
--{
--        /*
--         * Load the stream structure for the next traversal.  Since we don't
--         * actually enter the directory until after the preorder visit, set
--         * the fts_accpath field specially so the chdir gets done to the right
--         * place and the user can access the first node.  From fts_open it's
--         * known that the file name will fit.
--         */
--        register size_t len = p->fts_pathlen = p->fts_namelen;
--        memmove(sp->fts_path, p->fts_name, len + 1);
--        register char *cp = strrchr(p->fts_name, '/');
--        if (cp && (cp != p->fts_name || cp[1])) {
--                len = strlen(++cp);
--                memmove(p->fts_name, cp, len + 1);
--                p->fts_namelen = len;
--        }
--        p->fts_accpath = p->fts_path = sp->fts_path;
--}
--
--int
--FTS_CLOSE (FTSOBJ *sp)
--{
--        /*
--         * This still works if we haven't read anything -- the dummy structure
--         * points to the root list, so we step through to the end of the root
--         * list which has a valid parent pointer.
--         */
--        if (sp->fts_cur) {
--                register FTSENTRY *p;
--                for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
--                        register FTSENTRY *freep = p;
--                        p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
--                        free(FTSENT_WRAPPER(freep));
--                }
--                free(FTSENT_WRAPPER(p));
--        }
--
--        /* Free up child linked list, sort array, file name buffer. */
--        if (sp->fts_child)
--                fts_lfree(sp->fts_child);
--        free(sp->fts_array);
--        free(sp->fts_path);
--
--        int saved_errno = 0;
--        if (ISSET(FTS_CWDFD))
--          {
--            if (0 <= sp->fts_cwd_fd)
--              if (close (sp->fts_cwd_fd))
--                saved_errno = errno;
--          }
--        else if (!ISSET(FTS_NOCHDIR))
--          {
--            /* Return to original directory, save errno if necessary. */
--            if (fchdir(sp->fts_rfd))
--              saved_errno = errno;
--
--            /* If close fails, record errno only if saved_errno is zero,
--               so that we report the probably-more-meaningful fchdir errno.  */
--            if (close (sp->fts_rfd))
--              if (saved_errno == 0)
--                saved_errno = errno;
--          }
--
--        fd_ring_clear (&sp->fts_fd_ring);
--
--        if (sp->fts_leaf_optimization_works_ht)
--          hash_free (sp->fts_leaf_optimization_works_ht);
--
--        free_dir (sp);
--
--        /* Free up the stream pointer. */
--        free(sp);
--
--        /* Set errno and return. */
--        if (saved_errno) {
--                __set_errno (saved_errno);
--                return (-1);
--        }
--
--        return (0);
--}
--
--/* Minimum link count of a traditional Unix directory.  When leaf
--   optimization is OK and a directory's st_nlink == MIN_DIR_NLINK,
--   then the directory has no subdirectories.  */
--enum { MIN_DIR_NLINK = 2 };
--
--/* Whether leaf optimization is OK for a directory.  */
--enum leaf_optimization
--  {
--    /* st_nlink is not reliable for this directory's subdirectories.  */
--    NO_LEAF_OPTIMIZATION,
--
--    /* st_nlink == 2 means the directory lacks subdirectories.  */
--    OK_LEAF_OPTIMIZATION
--  };
--
--#if (defined __linux__ || defined __ANDROID__) \
--  && HAVE_SYS_VFS_H && HAVE_FSTATFS && HAVE_STRUCT_STATFS_F_TYPE
--
--# include <sys/vfs.h>
--
--/* Linux-specific constants from coreutils' src/fs.h */
--# define S_MAGIC_AFS 0x5346414F
--# define S_MAGIC_CIFS 0xFF534D42
--# define S_MAGIC_LUSTRE 0x0BD00BD0
--# define S_MAGIC_NFS 0x6969
--# define S_MAGIC_PROC 0x9FA0
--# define S_MAGIC_TMPFS 0x1021994
--
--# ifdef HAVE___FSWORD_T
--typedef __fsword_t fsword;
--# else
--typedef long int fsword;
--# endif
--
--/* Map a stat.st_dev number to a file system type number f_ftype.  */
--struct dev_type
--{
--  dev_t st_dev;
--  fsword f_type;
--};
--
--/* Use a tiny initial size.  If a traversal encounters more than
--   a few devices, the cost of growing/rehashing this table will be
--   rendered negligible by the number of inodes processed.  */
--enum { DEV_TYPE_HT_INITIAL_SIZE = 13 };
--
--static size_t
--dev_type_hash (void const *x, size_t table_size)
--{
--  struct dev_type const *ax = x;
--  uintmax_t dev = ax->st_dev;
--  return dev % table_size;
--}
--
--static bool
--dev_type_compare (void const *x, void const *y)
--{
--  struct dev_type const *ax = x;
--  struct dev_type const *ay = y;
--  return ax->st_dev == ay->st_dev;
--}
--
--/* Return the file system type of P with file descriptor FD, or 0 if not known.
--   If FD is negative, P's file descriptor is unavailable.
--   Try to cache known values.  */
--
--static fsword
--filesystem_type (FTSENTRY const *p, int fd)
--{
--  FTSOBJ *sp = FTSENT_FTS(p);
--
--  /* If we're not in CWDFD mode, don't bother with this optimization,
--     since the caller is not serious about performance.  */
--  if (!ISSET (FTS_CWDFD))
--    return 0;
--
--  Hash_table *h = sp->fts_leaf_optimization_works_ht;
--  if (! h)
--    h = sp->fts_leaf_optimization_works_ht
--      = hash_initialize (DEV_TYPE_HT_INITIAL_SIZE, NULL, dev_type_hash,
--                         dev_type_compare, free);
--
--  if (h)
--    {
--      struct dev_type tmp;
--      tmp.st_dev = p->fts_statp->st_dev;
--      struct dev_type *ent = hash_lookup (h, &tmp);
--      if (ent)
--        return ent->f_type;
--    }
--
--  /* Look-up failed.  Query directly and cache the result.  */
--  struct STRUCT_STATFS fs_buf;
--  if (fd < 0 || FSTATFS (fd, &fs_buf) != 0)
--    return 0;
--
--  if (h)
--    {
--      struct dev_type *t2 = malloc (sizeof *t2);
--      if (t2)
--        {
--          t2->st_dev = p->fts_statp->st_dev;
--          t2->f_type = fs_buf.f_type;
--
--          struct dev_type *ent = hash_insert (h, t2);
--          if (ent)
--            fts_assert (ent == t2);
--          else
--            free (t2);
--        }
--    }
--
--  return fs_buf.f_type;
--}
--
--/* Return true if sorting dirents on inode numbers is known to improve
--   traversal performance for the directory P with descriptor DIR_FD.
--   Return false otherwise.  When in doubt, return true.
--   DIR_FD is negative if unavailable.  */
--static bool
--dirent_inode_sort_may_be_useful (FTSENTRY const *p, int dir_fd)
--{
--  /* Skip the sort only if we can determine efficiently
--     that skipping it is the right thing to do.
--     The cost of performing an unnecessary sort is negligible,
--     while the cost of *not* performing it can be O(N^2) with
--     a very large constant.  */
--
--  switch (filesystem_type (p, dir_fd))
--    {
--    case S_MAGIC_LUSTRE:
--      /* On Lustre, sorting directory entries interferes with its ability to
--         prefetch file metadata (via statahead).  This would make a command
--         like 'du' around 9 times slower.  See
--         <https://bugs.gnu.org/80106>.  */
--    case S_MAGIC_CIFS:
--    case S_MAGIC_NFS:
--    case S_MAGIC_TMPFS:
--      /* On a file system of any of these types, sorting
--         is unnecessary, and hence wasteful.  */
--      return false;
--
--    default:
--      return true;
--    }
--}
--
--/* Given an FTS entry P for a directory with descriptor DIR_FD,
--   return whether it is valid to apply leaf optimization.
--   The optimization is valid if a directory's st_nlink value equal
--   to MIN_DIR_NLINK means the directory has no subdirectories.
--   DIR_FD is negative if unavailable.  */
--static enum leaf_optimization
--leaf_optimization (FTSENTRY const *p, int dir_fd)
--{
--  switch (filesystem_type (p, dir_fd))
--    {
--    case 0:
--      /* Leaf optimization is unsafe if the file system type is unknown.  */
--      FALLTHROUGH;
--    case S_MAGIC_AFS:
--      /* Although AFS mount points are not counted in st_nlink, they
--         act like directories.  See <https://bugs.debian.org/143111>.  */
--      FALLTHROUGH;
--    case S_MAGIC_CIFS:
--      /* Leaf optimization causes 'find' to abort.  See
--         <https://lists.gnu.org/r/bug-gnulib/2018-04/msg00015.html>.  */
--      FALLTHROUGH;
--    case S_MAGIC_NFS:
--      /* NFS provides usable dirent.d_type but not necessarily for all entries
--         of large directories, so as per <https://bugzilla.redhat.com/1252549>
--         NFS should return true.  However st_nlink values are not accurate on
--         all implementations as per <https://bugzilla.redhat.com/1299169>.  */
--      FALLTHROUGH;
--    case S_MAGIC_PROC:
--      /* Per <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=143111> /proc
--         may have bogus stat.st_nlink values.  */
--      return NO_LEAF_OPTIMIZATION;
--
--    default:
--      return OK_LEAF_OPTIMIZATION;
--    }
--}
--
--#else
--static bool
--dirent_inode_sort_may_be_useful (_GL_UNUSED FTSENTRY const *p,
--                                 _GL_UNUSED int dir_fd)
--{
--  return true;
--}
--static enum leaf_optimization
--leaf_optimization (_GL_UNUSED FTSENTRY const *p, _GL_UNUSED int dir_fd)
--{
--  return NO_LEAF_OPTIMIZATION;
--}
--#endif
--
--/*
-- * Special case of "/" at the end of the file name so that slashes aren't
-- * appended which would cause file names to be written as "....//foo".
-- */
--#define NAPPEND(p)                                                      \
--        (p->fts_path[p->fts_pathlen - 1] == '/'                         \
--            ? p->fts_pathlen - 1 : p->fts_pathlen)
--
--FTSENTRY *
--FTS_READ (FTSOBJ *sp)
--{
--        /* If finished or unrecoverable error, return NULL. */
--        if (sp->fts_cur == NULL || ISSET(FTS_STOP))
--                return (NULL);
--
--        /* Set current node pointer. */
--        register FTSENTRY *p = sp->fts_cur;
--
--        /* Save and zero out user instructions. */
--        register unsigned short int instr = p->fts_instr;
--        p->fts_instr = FTS_NOINSTR;
--
--        /* Any type of file may be re-visited; re-stat and re-turn. */
--        if (instr == FTS_AGAIN) {
--                p->fts_info = fts_stat(sp, p, false);
--                return (p);
--        }
--        Dprintf (("fts_read: p=%s\n",
--                  p->fts_info == FTS_INIT ? "" : p->fts_path));
--
--        /*
--         * Following a symlink -- SLNONE test allows application to see
--         * SLNONE and recover.  If indirecting through a symlink, have
--         * keep a pointer to current location.  If unable to get that
--         * pointer, follow fails.
--         */
--        if (instr == FTS_FOLLOW &&
--            (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
--                p->fts_info = fts_stat(sp, p, true);
--                if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
--                        if ((p->fts_symfd = diropen (sp, ".")) < 0) {
--                                p->fts_errno = errno;
--                                p->fts_info = FTS_ERR;
--                        } else
--                                p->fts_flags |= FTS_SYMFOLLOW;
--                }
--                goto check_for_dir;
--        }
--
--        /* Directory in pre-order. */
--        if (p->fts_info == FTS_D) {
--                /* If skipped or crossed mount point, do post-order visit. */
--                if (instr == FTS_SKIP ||
--                    (ISSET(FTS_XDEV) && p->fts_statp->st_dev != sp->fts_dev)) {
--                        if (p->fts_flags & FTS_SYMFOLLOW)
--                                (void)close(p->fts_symfd);
--                        if (sp->fts_child) {
--                                fts_lfree(sp->fts_child);
--                                sp->fts_child = NULL;
--                        }
--                        p->fts_info = FTS_DP;
--                        LEAVE_DIR (sp, p, "1");
--                        return (p);
--                }
--
--                /* Rebuild if only read the names and now traversing. */
--                if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
--                        CLR(FTS_NAMEONLY);
--                        fts_lfree(sp->fts_child);
--                        sp->fts_child = NULL;
--                }
--
--                /*
--                 * Cd to the subdirectory.
--                 *
--                 * If have already read and now fail to chdir, whack the list
--                 * to make the names come out right, and set the parent errno
--                 * so the application will eventually get an error condition.
--                 * Set the FTS_DONTCHDIR flag so that when we logically change
--                 * directories back to the parent we don't do a chdir.
--                 *
--                 * If haven't read do so.  If the read fails, fts_build sets
--                 * FTS_STOP or the fts_info field of the node.
--                 */
--                if (sp->fts_child != NULL) {
--                        if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
--                                p->fts_errno = errno;
--                                p->fts_flags |= FTS_DONTCHDIR;
--                                for (p = sp->fts_child; p != NULL;
--                                     p = p->fts_link)
--                                        p->fts_accpath =
--                                            p->fts_parent->fts_accpath;
--                        }
--                } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
--                        if (ISSET(FTS_STOP))
--                                return (NULL);
--                        /* If fts_build's call to fts_safe_changedir failed
--                           because it was not able to fchdir into a
--                           subdirectory, tell the caller.  */
--                        if (p->fts_errno && p->fts_info != FTS_DNR)
--                                p->fts_info = FTS_ERR;
--                        LEAVE_DIR (sp, p, "2");
--                        return (p);
--                }
--                p = sp->fts_child;
--                sp->fts_child = NULL;
--                goto name;
--        }
--
--        /* Move to the next node on this level. */
--next: ;
--        register FTSENTRY *tmp = p;
--
--        /* If we have so many directory entries that we're reading them
--           in batches, and we've reached the end of the current batch,
--           read in a new batch.  */
--        if (p->fts_link == NULL && FTSENT_DIRP(p->fts_parent))
--          {
--            p = tmp->fts_parent;
--            sp->fts_cur = p;
--            sp->fts_path[p->fts_pathlen] = '\0';
--
--            if ((p = fts_build (sp, BREAD)) == NULL)
--              {
--                if (ISSET(FTS_STOP))
--                  return NULL;
--                goto cd_dot_dot;
--              }
--
--            free(FTSENT_WRAPPER(tmp));
--            goto name;
--          }
--
--        if ((p = p->fts_link) != NULL) {
--                sp->fts_cur = p;
--                free(FTSENT_WRAPPER(tmp));
--
--                /*
--                 * If reached the top, return to the original directory (or
--                 * the root of the tree), and load the file names for the next
--                 * root.
--                 */
--                if (p->fts_level == FTS_ROOTLEVEL) {
--                        if (restore_initial_cwd(sp)) {
--                                SET(FTS_STOP);
--                                return (NULL);
--                        }
--                        free_dir(sp);
--                        fts_load(sp, p);
--                        if (! setup_dir(sp)) {
--                                free_dir(sp);
--                                return (NULL);
--                        }
--                        goto check_for_dir;
--                }
--
--                /*
--                 * User may have called fts_set on the node.  If skipped,
--                 * ignore.  If followed, get a file descriptor so we can
--                 * get back if necessary.
--                 */
--                if (p->fts_instr == FTS_SKIP)
--                        goto next;
--                if (p->fts_instr == FTS_FOLLOW) {
--                        p->fts_info = fts_stat(sp, p, true);
--                        if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
--                                if ((p->fts_symfd = diropen (sp, ".")) < 0) {
--                                        p->fts_errno = errno;
--                                        p->fts_info = FTS_ERR;
--                                } else
--                                        p->fts_flags |= FTS_SYMFOLLOW;
--                        }
--                        p->fts_instr = FTS_NOINSTR;
--                }
--
--name:           {
--                  register char *t = sp->fts_path + NAPPEND(p->fts_parent);
--                  *t++ = '/';
--                  memmove(t, p->fts_name, p->fts_namelen + 1);
--                }
--check_for_dir:
--                sp->fts_cur = p;
--                if (p->fts_info == FTS_NSOK)
--                  {
--                    if (p->fts_statp->st_size == FTS_STAT_REQUIRED)
--                      p->fts_info = fts_stat(sp, p, false);
--                    else
--                      fts_assert (p->fts_statp->st_size == FTS_NO_STAT_REQUIRED);
--                  }
--
--                /* Skip files with different device numbers when FTS_MOUNT
--                   is set.  */
--                if (ISSET (FTS_MOUNT) && p->fts_info != FTS_NS &&
--                    p->fts_level != FTS_ROOTLEVEL &&
--                    p->fts_statp->st_dev != sp->fts_dev)
--                      goto next;
--
--                if (p->fts_info == FTS_D)
--                  {
--                    /* Now that P->fts_statp is guaranteed to be valid, if
--                       this is a command-line directory, record its device
--                       number, to be used for FTS_MOUNT and FTS_XDEV.  */
--                    if (p->fts_level == FTS_ROOTLEVEL)
--                      sp->fts_dev = p->fts_statp->st_dev;
--                    Dprintf (("  entering: %s\n", p->fts_path));
--                    if (! enter_dir (sp, p))
--                      return NULL;
--                  }
--                return p;
--        }
--cd_dot_dot:
--
--        /* Move up to the parent node. */
--        p = tmp->fts_parent;
--        sp->fts_cur = p;
--        free(FTSENT_WRAPPER(tmp));
--
--        if (p->fts_level == FTS_ROOTPARENTLEVEL) {
--                /*
--                 * Done; free everything up and set errno to 0 so the user
--                 * can distinguish between error and EOF.
--                 */
--                free(FTSENT_WRAPPER(p));
--                __set_errno (0);
--                return (sp->fts_cur = NULL);
--        }
--
--        fts_assert (p->fts_info != FTS_NSOK);
--
--        /* NUL terminate the file name.  */
--        sp->fts_path[p->fts_pathlen] = '\0';
--
--        /*
--         * Return to the parent directory.  If at a root node, restore
--         * the initial working directory.  If we came through a symlink,
--         * go back through the file descriptor.  Otherwise, move up
--         * one level, via "..".
--         */
--        if (p->fts_level == FTS_ROOTLEVEL) {
--                if (restore_initial_cwd(sp)) {
--                        p->fts_errno = errno;
--                        SET(FTS_STOP);
--                }
--        } else if (p->fts_flags & FTS_SYMFOLLOW) {
--                if (FCHDIR(sp, p->fts_symfd)) {
--                        p->fts_errno = errno;
--                        SET(FTS_STOP);
--                }
--                (void)close(p->fts_symfd);
--        } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
--                   fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
--                p->fts_errno = errno;
--                SET(FTS_STOP);
--        }
--
--        /* If the directory causes a cycle, preserve the FTS_DC flag and keep
--           the corresponding dev/ino pair in the hash table.  It is going to be
--           removed when leaving the original directory.  */
--        if (p->fts_info != FTS_DC) {
--                p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
--                if (p->fts_errno == 0)
--                        LEAVE_DIR (sp, p, "3");
--        }
--        return ISSET(FTS_STOP) ? NULL : p;
--}
--
--/*
-- * Fts_set takes the stream as an argument although it's not used in this
-- * implementation; it would be necessary if anyone wanted to add global
-- * semantics to fts using fts_set.  An error return is allowed for similar
-- * reasons.
-- */
--/* ARGSUSED */
--int
--FTS_SET (_GL_UNUSED FTSOBJ *sp, FTSENTRY *p, int instr)
--{
--        if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
--            instr != FTS_NOINSTR && instr != FTS_SKIP) {
--                __set_errno (EINVAL);
--                return (1);
--        }
--        p->fts_instr = instr;
--        return (0);
--}
--
--FTSENTRY *
--FTS_CHILDREN (FTSOBJ *sp, int instr)
--{
--        if (instr != 0 && instr != FTS_NAMEONLY) {
--                __set_errno (EINVAL);
--                return (NULL);
--        }
--
--        /* Set current node pointer. */
--        register FTSENTRY *p = sp->fts_cur;
--
--        /*
--         * Errno set to 0 so user can distinguish empty directory from
--         * an error.
--         */
--        __set_errno (0);
--
--        /* Fatal errors stop here. */
--        if (ISSET(FTS_STOP))
--                return (NULL);
--
--        /* Return logical hierarchy of user's arguments. */
--        if (p->fts_info == FTS_INIT)
--                return (p->fts_link);
--
--        /*
--         * If not a directory being visited in pre-order, stop here.  Could
--         * allow FTS_DNR, assuming the user has fixed the problem, but the
--         * same effect is available with FTS_AGAIN.
--         */
--        if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
--                return (NULL);
--
--        /* Free up any previous child list. */
--        if (sp->fts_child != NULL)
--                fts_lfree(sp->fts_child);
--
--        if (instr == FTS_NAMEONLY) {
--                SET(FTS_NAMEONLY);
--                instr = BNAMES;
--        } else
--                instr = BCHILD;
--
--        /*
--         * If using chdir on a relative file name and called BEFORE fts_read
--         * does its chdir to the root of a traversal, we can lose -- we need to
--         * chdir into the subdirectory, and we don't know where the current
--         * directory is, so we can't get back so that the upcoming chdir by
--         * fts_read will work.
--         */
--        if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
--            ISSET(FTS_NOCHDIR))
--                return (sp->fts_child = fts_build(sp, instr));
--
--        int fd = diropen (sp, ".");
--        if (fd < 0)
--                return (sp->fts_child = NULL);
--        sp->fts_child = fts_build(sp, instr);
--        if (ISSET(FTS_CWDFD))
--          {
--            cwd_advance_fd (sp, fd, true);
--          }
--        else
--          {
--            if (fchdir(fd))
--              {
--                int saved_errno = errno;
--                close (fd);
--                __set_errno (saved_errno);
--                return NULL;
--              }
--            close (fd);
--          }
--        return (sp->fts_child);
--}
--
--/* A comparison function to sort on increasing inode number.
--   For some file system types, sorting either way makes a huge
--   performance difference for a directory with very many entries,
--   but sorting on increasing values is slightly better than sorting
--   on decreasing values.  The difference is in the 5% range.  */
--static int
--fts_compare_ino (FTSENTRY const **a, FTSENTRY const **b)
--{
--  return _GL_CMP (a[0]->fts_statp->st_ino, b[0]->fts_statp->st_ino);
--}
--
--/* Map the dirent.d_type value, DTYPE, to the corresponding stat.st_mode
--   S_IF* bit and set ST.st_mode, thus clearing all other bits in that field.  */
--static void
--set_stat_type (struct STRUCT_STAT *st, unsigned int dtype)
--{
--  mode_t type;
--  switch (dtype)
--    {
--    case DT_BLK:
--      type = S_IFBLK;
--      break;
--    case DT_CHR:
--      type = S_IFCHR;
--      break;
--    case DT_DIR:
--      type = S_IFDIR;
--      break;
--    case DT_FIFO:
--      type = S_IFIFO;
--      break;
--    case DT_LNK:
--      type = S_IFLNK;
--      break;
--    case DT_REG:
--      type = S_IFREG;
--      break;
--    case DT_SOCK:
--      type = S_IFSOCK;
--      break;
--    default:
--      type = 0;
--    }
--  st->st_mode = type;
--}
--
--#define closedir_and_clear(dirp)                \
--  do                                            \
--    {                                           \
--      closedir (dirp);                          \
--      dirp = NULL;                              \
--    }                                           \
--  while (0)
--
--#define fts_opendir(file, Pdir_fd)                              \
--        OPENDIRAT((! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD)     \
--                   ? sp->fts_cwd_fd : AT_FDCWD),                \
--                  file,                                         \
--                  (((ISSET(FTS_PHYSICAL)                        \
--                     && ! (ISSET(FTS_COMFOLLOW)                 \
--                           && cur->fts_level == FTS_ROOTLEVEL)) \
--                    ? O_NOFOLLOW : 0)),                         \
--                  Pdir_fd)
--
--/*
-- * This is the tricky part -- do not casually change *anything* in here.  The
-- * idea is to build the linked list of entries that are used by fts_children
-- * and fts_read.  There are lots of special cases.
-- *
-- * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
-- * set and it's a physical walk (so that symbolic links can't be directories),
-- * we can do things quickly.  First, if it's a 4.4BSD file system, the type
-- * of the file is in the directory entry.  Otherwise, we assume that the number
-- * of subdirectories in a node is equal to the number of links to the parent.
-- * The former skips all stat calls.  The latter skips stat calls in any leaf
-- * directories and for any files after the subdirectories in the directory have
-- * been found, cutting the stat calls by about 2/3.
-- */
--static FTSENTRY *
--internal_function
--fts_build (register FTSOBJ *sp, int type)
--{
--        FTSENTRY *cur = sp->fts_cur;
--        bool continue_readdir = !!FTSENT_DIRP(cur);
--
--        /* When cur->fts_dirp is non-NULL, that means we should
--           continue calling readdir on that existing DIR* pointer
--           rather than opening a new one.  */
--        int dir_fd;
--        if (continue_readdir)
--          {
--            DIR *dp = FTSENT_DIRP(cur);
--            dir_fd = dirfd (dp);
--            if (dir_fd < 0)
--              {
--                int dirfd_errno = errno;
--                closedir_and_clear (FTSENT_DIRP(cur));
--                if (type == BREAD)
--                  {
--                    cur->fts_info = FTS_DNR;
--                    cur->fts_errno = dirfd_errno;
--                  }
--                return NULL;
--              }
--          }
--        else
--          {
--            /* Open the directory for reading.  If this fails, we're done.
--               If being called from fts_read, set the fts_info field. */
--            if ((FTSENT_DIRP (cur) = fts_opendir(cur->fts_accpath, &dir_fd)) == NULL)
--              {
--                if (type == BREAD)
--                  {
--                    cur->fts_info = FTS_DNR;
--                    cur->fts_errno = errno;
--                  }
--                return NULL;
--              }
--            /* Rather than calling fts_stat for each and every entry encountered
--               in the readdir loop (below), stat each directory only right after
--               opening it.  */
--            bool stat_optimization = cur->fts_info == FTS_NSOK;
--
--            if (stat_optimization
--                /* Also read the stat info again after opening a directory to
--                   reveal eventual changes caused by a submount triggered by
--                   the traversal.  But do it only for utilities which use
--                   FTS_TIGHT_CYCLE_CHECK.  Therefore, only find and du
--                   benefit/suffer from this feature for now.  */
--                || ISSET (FTS_TIGHT_CYCLE_CHECK))
--              {
--                if (!stat_optimization)
--                  LEAVE_DIR (sp, cur, "4");
--                if (FSTAT (dir_fd, cur->fts_statp) != 0)
--                  {
--                    int fstat_errno = errno;
--                    closedir_and_clear (FTSENT_DIRP(cur));
--                    if (type == BREAD)
--                      {
--                        cur->fts_errno = fstat_errno;
--                        cur->fts_info = FTS_NS;
--                      }
--                    __set_errno (fstat_errno);
--                    return NULL;
--                  }
--                if (stat_optimization)
--                  cur->fts_info = FTS_D;
--                else if (! enter_dir (sp, cur))
--                  {
--                    int saved_errno = errno;
--                    closedir_and_clear (FTSENT_DIRP(cur));
--                    __set_errno (saved_errno);
--                    return NULL;
--                  }
--              }
--          }
--
--        /* Maximum number of readdir entries to read at one time.  This
--           limitation is to avoid reading millions of entries into memory
--           at once.  When an fts_compar function is specified, we have no
--           choice: we must read all entries into memory before calling that
--           function.  But when no such function is specified, we can read
--           entries in batches that are large enough to help us with inode-
--           sorting, yet not so large that we risk exhausting memory.  */
--        size_t max_entries = sp->fts_compar ? SIZE_MAX : FTS_MAX_READDIR_ENTRIES;
--
--        /*
--         * If we're going to need to stat anything or we want to descend
--         * and stay in the directory, chdir.  If this fails we keep going,
--         * but set a flag so we don't chdir after the post-order visit.
--         * We won't be able to stat anything, but we can still return the
--         * names themselves.  Note, that since fts_read won't be able to
--         * chdir into the directory, it will have to return different file
--         * names than before, i.e. "a/b" instead of "b".  Since the node
--         * has already been visited in pre-order, have to wait until the
--         * post-order visit to return the error.  There is a special case
--         * here, if there was nothing to stat then it's not an error to
--         * not be able to stat.  This is all fairly nasty.  If a program
--         * needed sorted entries or stat information, they had better be
--         * checking FTS_NS on the returned nodes.
--         */
--        bool descend;
--        if (continue_readdir)
--          {
--            /* When resuming a short readdir run, we already have
--               the required dirp and dir_fd.  */
--            descend = true;
--          }
--        else
--          {
--            /* Try to descend unless it is a names-only fts_children,
--               or the directory is known to lack subdirectories.  */
--            descend = (type != BNAMES
--                       && ! (ISSET (FTS_NOSTAT) && ISSET (FTS_PHYSICAL)
--                             && ! ISSET (FTS_SEEDOT)
--                             && cur->fts_statp->st_nlink == MIN_DIR_NLINK
--                             && (leaf_optimization (cur, dir_fd)
--                                 != NO_LEAF_OPTIMIZATION)));
--            if (descend || type == BREAD)
--              {
--                if (ISSET(FTS_CWDFD))
--                  dir_fd = fcntl (dir_fd, F_DUPFD_CLOEXEC, STDERR_FILENO + 1);
--                if (dir_fd < 0 || fts_safe_changedir(sp, cur, dir_fd, NULL)) {
--                        if (descend && type == BREAD)
--                                cur->fts_errno = errno;
--                        cur->fts_flags |= FTS_DONTCHDIR;
--                        descend = false;
--                        closedir_and_clear(FTSENT_DIRP(cur));
--                        if (ISSET(FTS_CWDFD) && 0 <= dir_fd)
--                                close (dir_fd);
--                        FTSENT_DIRP(cur) = NULL;
--                } else
--                        descend = true;
--              }
--          }
--
--        /*
--         * Figure out the max file name length that can be stored in the
--         * current buffer -- the inner loop allocates more space as necessary.
--         * We really wouldn't have to do the maxlen calculations here, we
--         * could do them in fts_read before returning the name, but it's a
--         * lot easier here since the length is part of the dirent structure.
--         *
--         * If not changing directories set a pointer so that can just append
--         * each new component into the file name.
--         */
--        size_t len = NAPPEND(cur);
--        char *cp;
--        if (ISSET(FTS_NOCHDIR)) {
--                cp = sp->fts_path + len;
--                *cp++ = '/';
--        } else {
--                /* GCC, you're too verbose. */
--                cp = NULL;
--        }
--        len++;
--        size_t maxlen = sp->fts_pathlen - len;
--
--        ptrdiff_t level = cur->fts_level + 1;
--
--        /* Read the directory, attaching each entry to the "link" pointer. */
--        bool doadjust = false;
--        register FTSENTRY *head = NULL;
--        FTSENTRY *tail = NULL;
--        register size_t nitems = 0;
--        bool sort_by_inode = false;
--        while (FTSENT_DIRP(cur)) {
--                __set_errno (0);
--                struct dirent *dp = readdir(FTSENT_DIRP(cur));
--                if (dp == NULL) {
--                        /* Some readdir()s do not absorb ENOENT (dir
--                           deleted but open).  This bug was fixed in
--                           glibc 2.3 (2002).  */
--#if ! (2 < __GLIBC__ + (3 <= __GLIBC_MINOR__))
--                        if (errno == ENOENT)
--                          errno = 0;
--#endif
--                        if (errno) {
--                                cur->fts_errno = errno;
--                                /* If we've not read any items yet, treat
--                                   the error as if we can't access the dir.  */
--                                cur->fts_info = (continue_readdir || nitems)
--                                                ? FTS_ERR : FTS_DNR;
--                        }
--                        closedir_and_clear(FTSENT_DIRP(cur));
--                        break;
--                }
--                if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
--                        continue;
--
--                size_t d_namelen = _D_EXACT_NAMLEN (dp);
--                register FTSENTRY *p = fts_alloc (sp, dp->d_name, d_namelen);
--                if (!p)
--                        goto mem1;
--                if (d_namelen >= maxlen) {
--                        /* include space for NUL */
--                        uintptr_t oldaddr = (uintptr_t) sp->fts_path;
--                        if (! fts_palloc(sp, d_namelen + len + 1)) {
--                                /*
--                                 * No more memory.  Save
--                                 * errno, free up the current structure and the
--                                 * structures already allocated.
--                                 */
--mem1: ;
--                                int saved_errno = errno;
--                                free(FTSENT_WRAPPER(p));
--                                fts_lfree(head);
--                                closedir_and_clear(FTSENT_DIRP(cur));
--                                cur->fts_info = FTS_ERR;
--                                SET(FTS_STOP);
--                                __set_errno (saved_errno);
--                                return (NULL);
--                        }
--                        /* Did realloc() change the pointer? */
--                        if (oldaddr != (uintptr_t) sp->fts_path) {
--                                doadjust = true;
--                                if (ISSET(FTS_NOCHDIR))
--                                        cp = sp->fts_path + len;
--                        }
--                        maxlen = sp->fts_pathlen - len;
--                }
--
--                size_t new_len = len + d_namelen;
--                if (new_len < len) {
--                        /*
--                         * In the unlikely event that we would end up
--                         * with a file name longer than SIZE_MAX, free up
--                         * the current structure and the structures already
--                         * allocated, then error out with ENAMETOOLONG.
--                         */
--                        free(FTSENT_WRAPPER(p));
--                        fts_lfree(head);
--                        closedir_and_clear(FTSENT_DIRP(cur));
--                        cur->fts_info = FTS_ERR;
--                        SET(FTS_STOP);
--                        __set_errno (ENAMETOOLONG);
--                        return (NULL);
--                }
--                p->fts_level = level;
--                p->fts_parent = sp->fts_cur;
--                p->fts_pathlen = new_len;
--
--                /* Store dirent.d_ino, in case we need to sort
--                   entries before processing them.  */
--                p->fts_statp->st_ino = D_INO (dp);
--
--                /* Build a file name for fts_stat to stat. */
--                if (ISSET(FTS_NOCHDIR)) {
--                        p->fts_accpath = p->fts_path;
--                        memmove(cp, p->fts_name, p->fts_namelen + 1);
--                } else
--                        p->fts_accpath = p->fts_name;
--
--                if (sp->fts_compar == NULL || ISSET(FTS_DEFER_STAT)) {
--                        /* Record what fts_read will have to do with this
--                           entry. In many cases, it will simply fts_stat it,
--                           but we can take advantage of any d_type information
--                           to optimize away the unnecessary stat calls.  I.e.,
--                           if FTS_NOSTAT is in effect, we don't need device
--                           numbers unconditionally (FTS_MOUNT) and we're not
--                           following symlinks (FTS_PHYSICAL) and d_type
--                           indicates this is *not* a directory, then we won't
--                           have to stat it  at all.  If it *is* a directory,
--                           then (currently) we stat it regardless, in order to
--                           get device and inode numbers.  Some day we might
--                           optimize that away, too, for directories where
--                           d_ino is known to be valid.  */
--                        bool skip_stat = (ISSET(FTS_NOSTAT)
--                                          && DT_IS_KNOWN(dp)
--                                          && ! DT_MUST_BE(dp, DT_DIR)
--                                          && (ISSET(FTS_PHYSICAL)
--                                              || ! DT_MUST_BE(dp, DT_LNK))
--                                          && ! ISSET(FTS_MOUNT));
--                        p->fts_info = FTS_NSOK;
--                        /* Propagate dirent.d_type information back
--                           to caller, when possible.  */
--                        set_stat_type (p->fts_statp, D_TYPE (dp));
--                        fts_set_stat_required(p, !skip_stat);
--                } else {
--                        p->fts_info = fts_stat(sp, p, false);
--                }
--
--                /* We walk in directory order so "ls -f" doesn't get upset. */
--                p->fts_link = NULL;
--                if (head == NULL)
--                        head = tail = p;
--                else {
--                        tail->fts_link = p;
--                        tail = p;
--                }
--
--                /* If there are many entries, no sorting function has been
--                   specified, and this file system is of a type that may be
--                   slow with a large number of entries, arrange to sort the
--                   directory entries on increasing inode numbers.
--
--                   The NITEMS comparison uses ==, not >, because the test
--                   needs to be tried at most once once, and NITEMS will exceed
--                   the threshold after it is incremented below.  */
--                if (nitems == _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
--                    && !sp->fts_compar)
--                  sort_by_inode = dirent_inode_sort_may_be_useful (cur, dir_fd);
--
--                ++nitems;
--                if (max_entries <= nitems) {
--                        /* When there are too many dir entries, leave
--                           fts_dirp open, so that a subsequent fts_read
--                           can take up where we leave off.  */
--                        break;
--                }
--        }
--
--        /*
--         * If realloc() changed the address of the file name, adjust the
--         * addresses for the rest of the tree and the dir list.
--         */
--        if (doadjust)
--                fts_padjust(sp, head);
--
--        /*
--         * If not changing directories, reset the file name back to original
--         * state.
--         */
--        if (ISSET(FTS_NOCHDIR)) {
--                if (len == sp->fts_pathlen || nitems == 0)
--                        --cp;
--                *cp = '\0';
--        }
--
--        /*
--         * If descended after called from fts_children or after called from
--         * fts_read and nothing found, get back.  At the root level we use
--         * the saved fd; if one of fts_open()'s arguments is a relative name
--         * to an empty directory, we wind up here with no other way back.  If
--         * can't get back, we're done.
--         */
--        if (!continue_readdir && descend && (type == BCHILD || !nitems) &&
--            (cur->fts_level == FTS_ROOTLEVEL
--             ? restore_initial_cwd(sp)
--             : fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
--                cur->fts_info = FTS_ERR;
--                SET(FTS_STOP);
--                fts_lfree(head);
--                return (NULL);
--        }
--
--        /* If didn't find anything, return NULL. */
--        if (!nitems) {
--                if (type == BREAD
--                    && cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR)
--                        cur->fts_info = FTS_DP;
--                fts_lfree(head);
--                return (NULL);
--        }
--
--        if (sort_by_inode) {
--                sp->fts_compar = FTS_COMPAR_CAST (fts_compare_ino);
--                head = fts_sort (sp, head, nitems);
--                sp->fts_compar = NULL;
--        }
--
--        /* Sort the entries. */
--        if (sp->fts_compar && nitems > 1)
--                head = fts_sort(sp, head, nitems);
--        return (head);
--}
--
--#if GNULIB_FTS_DEBUG
--
--struct devino {
--  intmax_t dev, ino;
--};
--#define PRINT_DEVINO "(%jd,%jd)"
--
--static struct devino
--getdevino (int fd)
--{
--  struct STRUCT_STAT st;
--  return (fd == AT_FDCWD
--          ? (struct devino) { -1, 0 }
--          : FSTAT (fd, &st) == 0
--          ? (struct devino) { st.st_dev, st.st_ino }
--          : (struct devino) { -1, errno });
--}
--
--/* Walk ->fts_parent links starting at E_CURR, until the root of the
--   current hierarchy.  There should be a directory with dev/inode
--   matching those of AD.  If not, print a lot of diagnostics.  */
--static void
--find_matching_ancestor (FTSENTRY const *e_curr, struct Active_dir const *ad)
--{
--  for (FTSENTRY const *ent = e_curr;
--       ent->fts_level >= FTS_ROOTLEVEL;
--       ent = ent->fts_parent)
--    {
--      if (ad->ino == ent->fts_statp->st_ino
--          && ad->dev == ent->fts_statp->st_dev)
--        return;
--    }
--  printf ("ERROR: tree dir, %s, not active\n", ad->fts_ent->fts_accpath);
--  printf ("active dirs:\n");
--  for (FTSENTRY const *ent = e_curr;
--       ent->fts_level >= FTS_ROOTLEVEL;
--       ent = ent->fts_parent)
--    printf ("  %s(%"PRIuMAX"/%"PRIuMAX") to %s(%"PRIuMAX"/%"PRIuMAX")...\n",
--            ad->fts_ent->fts_accpath,
--            (uintmax_t) ad->dev,
--            (uintmax_t) ad->ino,
--            ent->fts_accpath,
--            (uintmax_t) ent->fts_statp->st_dev,
--            (uintmax_t) ent->fts_statp->st_ino);
--}
--
--void
--fts_cross_check (FTSOBJ const *sp)
--{
--  if ( ! ISSET (FTS_TIGHT_CYCLE_CHECK))
--    return;
--
--  FTSENTRY const *ent = sp->fts_cur;
--
--  Dprintf (("fts-cross-check cur=%s\n", ent->fts_path));
--  /* Make sure every parent dir is in the tree.  */
--  for (FTSENTRY const *t = ent->fts_parent;
--       t->fts_level >= FTS_ROOTLEVEL;
--       t = t->fts_parent)
--    {
--      struct Active_dir ad;
--      ad.ino = t->fts_statp->st_ino;
--      ad.dev = t->fts_statp->st_dev;
--      if ( ! hash_lookup (sp->fts_cycle.ht, &ad))
--        printf ("ERROR: active dir, %s, not in tree\n", t->fts_path);
--    }
--
--  /* Make sure every dir in the tree is an active dir.
--     But ENT is not necessarily a directory.  If so, just skip this part. */
--  if (ent->fts_parent->fts_level >= FTS_ROOTLEVEL
--      && (ent->fts_info == FTS_DP
--          || ent->fts_info == FTS_D))
--    for (struct Active_dir *ad = hash_get_first (sp->fts_cycle.ht);
--         ad != NULL;
--         ad = hash_get_next (sp->fts_cycle.ht, ad))
--      {
--        find_matching_ancestor (ent, ad);
--      }
--}
--
--static bool
--same_fd (int fd1, int fd2)
--{
--  struct STRUCT_STAT sb1, sb2;
--  return (FSTAT (fd1, &sb1) == 0
--          && FSTAT (fd2, &sb2) == 0
--          && psame_inode (&sb1, &sb2));
--}
--
--static void
--fd_ring_print (FTSOBJ const *sp, FILE *stream, char const *msg)
--{
--  if (!fts_debug)
--    return;
--  I_ring const *fd_ring = &sp->fts_fd_ring;
--  struct devino cwd = getdevino (sp->fts_cwd_fd);
--  fprintf (stream, "=== %s ========== "PRINT_DEVINO"\n", msg, cwd.dev, cwd.ino);
--  if (i_ring_empty (fd_ring))
--    return;
--
--  unsigned int i = fd_ring->ir_front;
--  while (true)
--    {
--      int fd = fd_ring->ir_data[i];
--      if (fd < 0)
--        fprintf (stream, "%u: %d:\n", i, fd);
--      else
--        {
--          struct devino wd = getdevino (fd);
--          fprintf (stream, "%u: %d: "PRINT_DEVINO"\n", i, fd, wd.dev, wd.ino);
--        }
--      if (i == fd_ring->ir_back)
--        break;
--      i = (i + I_RING_SIZE - 1) % I_RING_SIZE;
--    }
--}
--
--/* Ensure that each file descriptor on the fd_ring matches a
--   parent, grandparent, etc. of the current working directory.  */
--static void
--fd_ring_check (FTSOBJ const *sp)
--{
--  if (!fts_debug)
--    return;
--
--  /* Make a writable copy.  */
--  I_ring fd_w = sp->fts_fd_ring;
--
--  int cwd_fd = sp->fts_cwd_fd;
--  cwd_fd = fcntl (cwd_fd, F_DUPFD_CLOEXEC, STDERR_FILENO + 1);
--  struct devino dot = getdevino (cwd_fd);
--  fprintf (stderr, "===== check ===== cwd: "PRINT_DEVINO"\n",
--           dot.dev, dot.ino);
--  while ( ! i_ring_empty (&fd_w))
--    {
--      int fd = i_ring_pop (&fd_w);
--      if (0 <= fd)
--        {
--          int open_flags = O_SEARCH | O_CLOEXEC;
--          int parent_fd = openat (cwd_fd, "..", open_flags);
--          if (parent_fd < 0)
--            {
--              // Warn?
--              break;
--            }
--          if (!same_fd (fd, parent_fd))
--            {
--              struct devino cwd = getdevino (fd);
--              fprintf (stderr, "ring  : "PRINT_DEVINO"\n", cwd.dev, cwd.ino);
--              struct devino c2 = getdevino (parent_fd);
--              fprintf (stderr, "parent: "PRINT_DEVINO"\n", c2.dev, c2.ino);
--              fts_assert (0);
--            }
--          close (cwd_fd);
--          cwd_fd = parent_fd;
--        }
--    }
--  close (cwd_fd);
--}
--#endif
--
--static unsigned short int
--internal_function
--fts_stat(FTSOBJ *sp, register FTSENTRY *p, bool follow)
--{
--        if (ISSET (FTS_LOGICAL)
--            || (ISSET (FTS_COMFOLLOW) && p->fts_level == FTS_ROOTLEVEL))
--                follow = true;
--
--        struct STRUCT_STAT *sbp = p->fts_statp;
--
--        /*
--         * If doing a logical walk, or application requested FTS_FOLLOW, do
--         * a stat(2).  If that fails, check for a nonexistent symlink.  If
--         * fail, set the errno from the stat call.
--         */
--        int flags = follow ? 0 : AT_SYMLINK_NOFOLLOW;
--        if (FSTATAT (sp->fts_cwd_fd, p->fts_accpath, sbp, flags) < 0)
--          {
--            if (follow && errno == ENOENT
--                && 0 <= FSTATAT (sp->fts_cwd_fd, p->fts_accpath, sbp,
--                                 AT_SYMLINK_NOFOLLOW))
--              {
--                __set_errno (0);
--                return FTS_SLNONE;
--              }
--
--            p->fts_errno = errno;
--           memset (sbp, 0, sizeof *sbp);
--            return FTS_NS;
--          }
--
--        if (S_ISDIR(sbp->st_mode)) {
--                if (ISDOT(p->fts_name)) {
--                        /* Command-line "." and ".." are real directories. */
--                        return (p->fts_level == FTS_ROOTLEVEL ? FTS_D : FTS_DOT);
--                }
--
--                return (FTS_D);
--        }
--        if (S_ISLNK(sbp->st_mode))
--                return (FTS_SL);
--        if (S_ISREG(sbp->st_mode))
--                return (FTS_F);
--        return (FTS_DEFAULT);
--}
--
--static int
--fts_compar (void const *a, void const *b)
--{
--  /* Convert A and B to the correct types, to pacify the compiler, and
--     for portability to bizarre hosts where "void const *" and "FTSENT
--     const **" differ in runtime representation.  The comparison
--     function cannot modify *a and *b, but there is no compile-time
--     check for this.  */
--  FTSENTRY const **pa = (FTSENTRY const **) a;
--  FTSENTRY const **pb = (FTSENTRY const **) b;
--  return FTSENT_FTS(pa[0])->fts_compar (pa, pb);
--}
--
--static FTSENTRY *
--internal_function
--fts_sort (FTSOBJ *sp, FTSENTRY *head, register size_t nitems)
--{
--        register FTSENTRY **ap, *p;
--
--        /* On most modern hosts, void * and FTSENT ** have the same
--           run-time representation, and one can convert sp->fts_compar to
--           the type qsort expects without problem.  Use the heuristic that
--           this is OK if the two pointer types are the same size, and if
--           converting FTSENT ** to uintptr_t is the same as converting
--           FTSENT ** to void * and then to uintptr_t.  This heuristic isn't
--           valid in general but we don't know of any counterexamples.  */
--        FTSENTRY *dummy;
--        int (*compare) (void const *, void const *) =
--          ((sizeof &dummy == sizeof (void *)
--            && (uintptr_t) &dummy == (uintptr_t) (void *) &dummy)
--           ? (int (*) (void const *, void const *)) sp->fts_compar
--           : fts_compar);
--
--        /*
--         * Construct an array of pointers to the structures and call qsort(3).
--         * Reassemble the array in the order returned by qsort.  If unable to
--         * sort for memory reasons, return the directory entries in their
--         * current order.  Allocate enough space for the current needs plus
--         * 40 so don't realloc one entry at a time.
--         */
--        if (nitems > sp->fts_nitems) {
--                sp->fts_nitems = nitems + 40;
--                FTSENTRY **a;
--                if (! (a = reallocarray (sp->fts_array,
--                                         sp->fts_nitems, sizeof *a))) {
--                        free(sp->fts_array);
--                        sp->fts_array = NULL;
--                        sp->fts_nitems = 0;
--                        return (head);
--                }
--                sp->fts_array = a;
--        }
--        for (ap = sp->fts_array, p = head; p; p = p->fts_link)
--                *ap++ = p;
--        qsort((void *)sp->fts_array, nitems, sizeof(FTSENTRY *), compare);
--        for (head = *(ap = sp->fts_array); --nitems; ++ap)
--                ap[0]->fts_link = ap[1];
--        ap[0]->fts_link = NULL;
--        return (head);
--}
--
--static FTSENTRY *
--internal_function
--fts_alloc (FTSOBJ *sp, const char *name, register size_t namelen)
--{
--        /*
--         * The file name is a variable length array.  Allocate the FTSENT
--         * structure and the file name in one chunk.
--         */
--        size_t len = FLEXSIZEOF(FTSENT, fts_name, namelen + 1);
--	register FTSENTRY *p;
--#if !_LIBC
--        p = malloc(len);
--        if (p == NULL)
--                return (NULL);
--#else
--	/*
--	 * For glibc, we use a wrapper struct to provide the extra required
--	 * fields without changing the FSENT layout.
--	 */
--	len += sizeof (struct FTSENT_wrapper);
--	struct FTSENT_wrapper *wrapper = malloc(len);
--	if (wrapper == NULL)
--		return (NULL);
--	p = &wrapper->ent;
--        p->fts_statp = &wrapper->fts_stat;
--#endif
--
--        /* Copy the name and guarantee NUL termination. */
--        memcpy(p->fts_name, name, namelen);
--        p->fts_name[namelen] = '\0';
--
--        p->fts_namelen = namelen;
--        FTSENT_FTS(p)= sp;
--        p->fts_path = sp->fts_path;
--        p->fts_errno = 0;
--        FTSENT_DIRP(p) = NULL;
--        p->fts_flags = 0;
--        p->fts_instr = FTS_NOINSTR;
--        p->fts_number = 0;
--        p->fts_pointer = NULL;
--        return (p);
--}
--
--static void
--internal_function
--fts_lfree (register FTSENTRY *head)
--{
--        int saved_errno = errno;
--
--        /* Free a linked list of structures. */
--        register FTSENTRY *p;
--        while ((p = head)) {
--                head = head->fts_link;
--                if (FTSENT_DIRP(p))
--                        closedir (FTSENT_DIRP(p));
--                free(FTSENT_WRAPPER(p));
--        }
--
--        __set_errno (saved_errno);
--}
--
--/*
-- * Allow essentially unlimited file name lengths; find, rm, ls should
-- * all work on any tree.  Most systems will allow creation of file
-- * names much longer than MAXPATHLEN, even though the kernel won't
-- * resolve them.  Add the size (not just what's needed) plus 256 bytes
-- * so don't realloc the file name 2 bytes at a time.
-- */
--static bool
--internal_function
--fts_palloc (FTSOBJ *sp, size_t more)
--{
--        size_t new_len = sp->fts_pathlen + more + 256;
--
--        /*
--         * See if fts_pathlen would overflow.
--         */
--        if (new_len < sp->fts_pathlen) {
--                free(sp->fts_path);
--                sp->fts_path = NULL;
--                __set_errno (ENAMETOOLONG);
--                return false;
--        }
--        sp->fts_pathlen = new_len;
--        char *p = realloc(sp->fts_path, sp->fts_pathlen);
--        if (p == NULL) {
--                free(sp->fts_path);
--                sp->fts_path = NULL;
--                return false;
--        }
--        sp->fts_path = p;
--        return true;
--}
--
--/*
-- * When the file name is realloc'd, have to fix all of the pointers in
-- *  structures already returned.
-- */
--static void
--internal_function
--fts_padjust (FTSOBJ *sp, FTSENTRY *head)
--{
--        char *addr = sp->fts_path;
--
--        /* This code looks at bit-patterns of freed pointers to
--           relocate them, so it relies on undefined behavior.  If this
--           trick does not work on your platform, please report a bug.  */
--
--#define ADJUST(p) do {                                                  \
--        uintptr_t old_accpath = (uintptr_t) (p)->fts_accpath;           \
--        if (old_accpath != (uintptr_t) (p)->fts_name) {                 \
--                (p)->fts_accpath =                                      \
--                  addr + (old_accpath - (uintptr_t) (p)->fts_path);     \
--        }                                                               \
--        (p)->fts_path = addr;                                           \
--} while (0)
--        /* Adjust the current set of children. */
--        for (FTSENTRY *p = sp->fts_child; p; p = p->fts_link)
--                ADJUST(p);
--
--        /* Adjust the rest of the tree, including the current level. */
--        for (FTSENTRY *p = head; p->fts_level >= FTS_ROOTLEVEL;) {
--                ADJUST(p);
--                p = p->fts_link ? p->fts_link : p->fts_parent;
--        }
--}
--
--static size_t
--internal_function _GL_ATTRIBUTE_PURE
--fts_maxarglen (char * const *argv)
--{
--        size_t max;
--
--        for (max = 0; *argv; ++argv) {
--                size_t len = strlen(*argv);
--                if (len > max)
--                        max = len;
--        }
--        return (max + 1);
--}
--
--/*
-- * Change to dir specified by fd or file name without getting
-- * tricked by someone changing the world out from underneath us.
-- * Assumes p->fts_statp->st_dev and p->fts_statp->st_ino are filled in.
-- * If FD is non-negative, expect it to be used after this function returns,
-- * and to be closed eventually.  So don't pass e.g., 'dirfd(dirp)' and then
-- * do closedir(dirp), because that would invalidate the saved FD.
-- * Upon failure, close FD immediately and return nonzero.
-- */
--static int
--internal_function
--fts_safe_changedir (FTSOBJ *sp, FTSENTRY *p, int fd, char const *dir)
--{
--        fts_assert (0 <= fd || dir != NULL);
--        bool is_dotdot = dir && streq (dir, "..");
--
--        /* This clause handles the unusual case in which FTS_NOCHDIR
--           is specified, along with FTS_CWDFD.  In that case, there is
--           no need to change even the virtual cwd file descriptor.
--           However, if FD is non-negative, we do close it here.  */
--        if (ISSET (FTS_NOCHDIR))
--          {
--            if (ISSET (FTS_CWDFD) && 0 <= fd)
--              close (fd);
--            return 0;
--          }
--
--        if (fd < 0 && is_dotdot && ISSET (FTS_CWDFD))
--          {
--            /* When possible, skip the diropen and subsequent fstat+dev/ino
--               comparison.  I.e., when changing to parent directory
--               (chdir ("..")), use a file descriptor from the ring and
--               save the overhead of diropen+fstat, as well as avoiding
--               failure when we lack "x" access to the virtual cwd.  */
--            if ( ! i_ring_empty (&sp->fts_fd_ring))
--              {
--                int parent_fd;
--                fd_ring_print (sp, stderr, "pre-pop");
--                parent_fd = i_ring_pop (&sp->fts_fd_ring);
--                if (0 <= parent_fd)
--                  {
--                    fd = parent_fd;
--                    dir = NULL;
--                  }
--              }
--          }
--
--        int newfd = fd;
--        if (fd < 0 && (newfd = diropen (sp, dir)) < 0)
--          return -1;
--
--        /* The following dev/inode check is necessary if we're doing a
--           "logical" traversal (through symlinks, a la chown -L), if the
--           system lacks O_NOFOLLOW support, or if we're changing to ".."
--           (but not via a popped file descriptor).  When changing to the
--           name "..", O_NOFOLLOW can't help.  In general, when the target is
--           not "..", diropen's use of O_NOFOLLOW ensures we don't mistakenly
--           follow a symlink, so we can avoid the expense of this fstat.  */
--        int ret;
--        if (ISSET(FTS_LOGICAL) || ! HAVE_WORKING_O_NOFOLLOW
--            || (dir && streq (dir, "..")))
--          {
--            struct STRUCT_STAT sb;
--            if (FSTAT (newfd, &sb))
--              {
--                ret = -1;
--                goto bail;
--              }
--            if (p->fts_statp->st_dev != sb.st_dev
--                || p->fts_statp->st_ino != sb.st_ino)
--              {
--                __set_errno (ENOENT);           /* disinformation */
--                ret = -1;
--                goto bail;
--              }
--          }
--
--        if (ISSET(FTS_CWDFD))
--          {
--            cwd_advance_fd (sp, newfd, ! is_dotdot);
--            return 0;
--          }
--
--        ret = fchdir(newfd);
--bail:
--        if (fd < 0)
--          {
--            int oerrno = errno;
--            (void)close(newfd);
--            __set_errno (oerrno);
--          }
--        return ret;
--}
-diff --git a/io/fts.c b/io/fts.c
-index d3b8e5a100f3213f..3825f0aeb4eb1594 100644
---- a/io/fts.c
-+++ b/io/fts.c
-@@ -1,23 +1,2208 @@
--/* File tree traversal functions LFS version.
--   Copyright (C) 2026 Free Software Foundation, Inc.
--   This file is part of the GNU C Library.
-+/* Traverse a file hierarchy.
- 
--   The GNU C Library is free software; you can redistribute it and/or
--   modify it under the terms of the GNU Lesser General Public
--   License as published by the Free Software Foundation; either
--   version 2.1 of the License, or (at your option) any later version.
-+   Copyright (C) 2004-2026 Free Software Foundation, Inc.
- 
--   The GNU C Library is distributed in the hope that it will be useful,
-+   This file is free software: you can redistribute it and/or modify
-+   it under the terms of the GNU Lesser General Public License as
-+   published by the Free Software Foundation; either version 2.1 of the
-+   License, or (at your option) any later version.
-+
-+   This file 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
--   Lesser General Public License for more details.
-+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+   GNU Lesser General Public License for more details.
-+
-+   You should have received a copy of the GNU Lesser General Public License
-+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
-+
-+/*-
-+ * Copyright (c) 1990, 1993, 1994
-+ *      The Regents of the University of California.  All rights reserved.
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions
-+ * are met:
-+ * 1. Redistributions of source code must retain the above copyright
-+ *    notice, this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright
-+ *    notice, this list of conditions and the following disclaimer in the
-+ *    documentation and/or other materials provided with the distribution.
-+ * 4. Neither the name of the University nor the names of its contributors
-+ *    may be used to endorse or promote products derived from this software
-+ *    without specific prior written permission.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
-+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-+ * SUCH DAMAGE.
-+ */
-+
-+#include <config.h>
-+
-+#if defined LIBC_SCCS && !defined GCC_LINT && !defined lint
-+static char sccsid[] = "@(#)fts.c       8.6 (Berkeley) 8/14/94";
-+#endif
-+
-+#if _LIBC
-+# include <fts.h>
-+#else
-+# include "fts_.h"
-+#endif
-+#if _LIBC || HAVE_SYS_PARAM_H
-+# include <sys/param.h>
-+#endif
-+#include <sys/stat.h>
-+#include <fcntl.h>
-+#include <errno.h>
-+#include <stddef.h>
-+#include <stdint.h>
-+#include <stdlib.h>
-+#include <string.h>
-+#include <unistd.h>
-+
-+/* Support for the LFS API version.  */
-+#ifndef FTS_OPEN
-+# define FTS_OPEN fts_open
-+# define FTS_CLOSE fts_close
-+# define FTS_READ fts_read
-+# define FTS_SET fts_set
-+# define FTS_CHILDREN fts_children
-+# define FTSOBJ FTS
-+# define FTSENTRY FTSENT
-+# define INO_T ino_t
-+# define STRUCT_STAT stat
-+# define FSTAT __fstat
-+# define FSTATAT __fstatat
-+# define STRUCT_STATFS statfs
-+# define FSTATFS __fstatfs
-+#endif
-+
-+#if ! _LIBC
-+# include "attribute.h"
-+# include "fcntl--.h"
-+# include "openat.h"
-+# include "opendirat.h"
-+# include "same-inode.h"
-+# define OPENDIRAT opendirat
-+# define FTSENT_WRAPPER(__p) __p
-+# define FTS_COMPAR_CAST(__fn) __fn
-+#else
-+# include <stdbool.h>
-+
-+# define internal_function
-+# define FALLTHROUGH               ; [[fallthrough]]
-+# define HAVE_STRUCT_DIRENT_D_TYPE 1
-+# define GNULIB_FTS_DEBUG          0
-+# ifdef O_PATH
-+#  define O_SEARCH                 O_PATH
-+# else
-+#  define O_SEARCH                 O_RDONLY
-+# endif
-+# define HAVE_SYS_VFS_H            1
-+# define HAVE_FSTATFS              1
-+# define HAVE_STRUCT_STATFS_F_TYPE 1
-+# define HAVE_OPENAT               1
-+# define HAVE_WORKING_O_NOFOLLOW   1
-+# define _GL_CMP(a, b)             ((a) < (b) ? -1 : (a) > (b))
-+# define OPENDIRAT                 __opendirat
-+
-+static inline bool openat_needs_fchdir (void)
-+{
-+  return false;
-+}
-+
-+static inline bool streq (const char *s1, const char *s2)
-+{
-+  return strcmp (s1, s2) == 0;
-+}
-+# define reallocarray              __libc_reallocarray
-+# define fchdir                    __fchdir
-+# define close                     __close
-+# define closedir                  __closedir
-+# define fcntl                     __fcntl
-+# define readdir                   __readdir
-+# ifndef dirfd
-+#  define dirfd                    __dirfd
-+# endif
-+# define open                      __open
-+# define openat                    __openat
- 
--   You should have received a copy of the GNU Lesser General Public
--   License along with the GNU C Library; if not, see
--   <https://www.gnu.org/licenses/>.  */
-+# include "cycle-check.c"
-+# include "i-ring.c"
- 
--#include <sys/types.h>
-+struct FTSENT_wrapper
-+{
-+  FTSOBJ *fts_fts;                /* the file hierarchy itself */
-+  DIR *fts_dirp;                  /* Dir pointer for any directory containing
-+				     more entries than we read at one time.  */
-+  struct STRUCT_STAT fts_stat;
- 
--#ifndef __OFF_T_MATCHES_OFF64_T
--# include "io/fts-common.c"
-+  FTSENTRY ent;
-+};
-+
-+/* glibc historicaly defines the FTS::fts_compar as having 'void *', while the
-+   fts_open has a function point using 'FTSENT **' as argument.  */
-+# define FTS_COMPAR_CAST(__fn) ((int (*) (void const *, void const *))__fn)
-+
-+# define FTSENT_WRAPPER(p) \
-+    ((struct FTSENT_wrapper *) ((char *)(p) - offsetof(struct FTSENT_wrapper, ent)))
-+#endif
-+#define FTSENT_FTS(p)   (FTSENT_WRAPPER(p)->fts_fts)
-+#define FTSENT_DIRP(p)  (FTSENT_WRAPPER(p)->fts_dirp)
-+
-+#include "flexmember.h"
-+
-+#include <dirent.h>
-+#ifndef _D_EXACT_NAMLEN
-+# define _D_EXACT_NAMLEN(dirent) strlen ((dirent)->d_name)
- #endif
-+
-+#if HAVE_STRUCT_DIRENT_D_TYPE
-+/* True if the type of the directory entry D is known.  */
-+# define DT_IS_KNOWN(d) ((d)->d_type != DT_UNKNOWN)
-+/* True if the type of the directory entry D must be T.  */
-+# define DT_MUST_BE(d, t) ((d)->d_type == (t))
-+# define D_TYPE(d) ((d)->d_type)
-+#else
-+# define DT_IS_KNOWN(d) false
-+# define DT_MUST_BE(d, t) false
-+# define D_TYPE(d) DT_UNKNOWN
-+
-+# undef DT_UNKNOWN
-+# define DT_UNKNOWN 0
-+
-+/* Any nonzero values will do here, so long as they're distinct.
-+   Undef any existing macros out of the way.  */
-+# undef DT_BLK
-+# undef DT_CHR
-+# undef DT_DIR
-+# undef DT_FIFO
-+# undef DT_LNK
-+# undef DT_REG
-+# undef DT_SOCK
-+# define DT_BLK 1
-+# define DT_CHR 2
-+# define DT_DIR 3
-+# define DT_FIFO 4
-+# define DT_LNK 5
-+# define DT_REG 6
-+# define DT_SOCK 7
-+#endif
-+
-+#ifndef S_IFBLK
-+# define S_IFBLK 0
-+#endif
-+#ifndef S_IFLNK
-+# define S_IFLNK 0
-+#endif
-+#ifndef S_IFSOCK
-+# define S_IFSOCK 0
-+#endif
-+
-+enum
-+{
-+  NOT_AN_INODE_NUMBER = 0
-+};
-+
-+#ifdef D_INO_IN_DIRENT
-+# define D_INO(dp) (dp)->d_ino
-+#else
-+/* Some systems don't have inodes, so fake them to avoid lots of ifdefs.  */
-+# define D_INO(dp) NOT_AN_INODE_NUMBER
-+#endif
-+
-+/* If possible (see max_entries, below), read no more than this many directory
-+   entries at a time.  Without this limit (i.e., when using non-NULL
-+   fts_compar), processing a directory with 4,000,000 entries requires ~1GiB
-+   of memory, and handling 64M entries would require 16GiB of memory.  */
-+#ifndef FTS_MAX_READDIR_ENTRIES
-+# define FTS_MAX_READDIR_ENTRIES 100000
-+#endif
-+
-+/* If there are more than this many entries in a directory,
-+   and the conditions mentioned below are satisfied, then sort
-+   the entries on inode number before any further processing.  */
-+#ifndef FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
-+# define FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD 10000
-+#endif
-+
-+enum
-+{
-+  _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD = FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
-+};
-+
-+enum Fts_stat
-+{
-+  FTS_NO_STAT_REQUIRED = 1,
-+  FTS_STAT_REQUIRED = 2
-+};
-+
-+#ifndef __set_errno
-+# define __set_errno(Val) errno = (Val)
-+#endif
-+
-+/* If this host provides the openat function, then we can avoid
-+   attempting to open "." in some initialization code below.  */
-+#ifdef HAVE_OPENAT
-+# define HAVE_OPENAT_SUPPORT 1
-+#else
-+# define HAVE_OPENAT_SUPPORT 0
-+#endif
-+
-+#ifdef NDEBUG
-+# define fts_assert(expr) ((void) (0 && (expr)))
-+#else
-+# define fts_assert(expr)       \
-+    do                          \
-+      {                         \
-+        if (!(expr))            \
-+          abort ();             \
-+      }                         \
-+    while (false)
-+#endif
-+
-+static FTSENTRY  *fts_alloc (FTSOBJ *, const char *, size_t);
-+static FTSENTRY  *fts_build (FTSOBJ *, int);
-+static void      fts_lfree (FTSENTRY *);
-+static void      fts_load (FTSOBJ *, FTSENTRY *);
-+static size_t    fts_maxarglen (char * const *);
-+static void      fts_padjust (FTSOBJ *, FTSENTRY *);
-+static bool      fts_palloc (FTSOBJ *, size_t);
-+static FTSENTRY  *fts_sort (FTSOBJ *, FTSENTRY *, size_t);
-+static unsigned short int fts_stat (FTSOBJ *, FTSENTRY *, bool);
-+static int      fts_safe_changedir (FTSOBJ *, FTSENTRY *, int, const char *);
-+
-+#include "fts-cycle.c"
-+
-+#ifndef MAX
-+# define MAX(a,b) ((a) > (b) ? (a) : (b))
-+#endif
-+
-+#ifndef SIZE_MAX
-+# define SIZE_MAX ((size_t) -1)
-+#endif
-+
-+#define ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
-+
-+#define CLR(opt)        (sp->fts_options &= ~(opt))
-+#define ISSET(opt)      ((sp->fts_options & (opt)) != 0)
-+#define SET(opt)        (sp->fts_options |= (opt))
-+
-+/* FIXME: FTS_NOCHDIR is now misnamed.
-+   Call it FTS_USE_FULL_RELATIVE_FILE_NAMES instead. */
-+#define FCHDIR(sp, fd)                                  \
-+  (!ISSET(FTS_NOCHDIR) && (ISSET(FTS_CWDFD)             \
-+                           ? (cwd_advance_fd ((sp), (fd), true), 0) \
-+                           : fchdir (fd)))
-+
-+
-+/* fts_build flags */
-+/* FIXME: make this an enum */
-+#define BCHILD          1               /* fts_children */
-+#define BNAMES          2               /* fts_children, names only */
-+#define BREAD           3               /* fts_read */
-+
-+#if GNULIB_FTS_DEBUG
-+# include <inttypes.h>
-+# include <stdio.h>
-+bool fts_debug = false;
-+# define Dprintf(x) do { if (fts_debug) printf x; } while (false)
-+static void fd_ring_check (FTSOBJ const *);
-+static void fd_ring_print (FTSOBJ const *, FILE *, char const *);
-+#else
-+# define Dprintf(x)
-+# define fd_ring_check(x)
-+# define fd_ring_print(a, b, c)
-+#endif
-+
-+#define LEAVE_DIR(Fts, Ent, Tag)                                \
-+  do                                                            \
-+    {                                                           \
-+      Dprintf (("  %s-leaving: %s\n", Tag, (Ent)->fts_path));   \
-+      leave_dir (Fts, Ent);                                     \
-+      fd_ring_check (Fts);                                      \
-+    }                                                           \
-+  while (false)
-+
-+static void
-+fd_ring_clear (I_ring *fd_ring)
-+{
-+  while ( ! i_ring_empty (fd_ring))
-+    {
-+      int fd = i_ring_pop (fd_ring);
-+      if (0 <= fd)
-+        close (fd);
-+    }
-+}
-+
-+/* Overload the fts_statp->st_size member (otherwise unused, when
-+   fts_info is FTS_NSOK) to indicate whether fts_read should stat
-+   this entry or not.  */
-+static void
-+fts_set_stat_required (FTSENTRY *p, bool required)
-+{
-+  fts_assert (p->fts_info == FTS_NSOK);
-+  p->fts_statp->st_size = (required
-+                           ? FTS_STAT_REQUIRED
-+                           : FTS_NO_STAT_REQUIRED);
-+}
-+
-+/* Virtual fchdir.  Advance SP's working directory file descriptor,
-+   SP->fts_cwd_fd, to FD, and push the previous value onto the fd_ring.
-+   CHDIR_DOWN_ONE is true if FD corresponds to an entry in the directory
-+   open on sp->fts_cwd_fd; i.e., to move the working directory one level
-+   down.  */
-+static void
-+internal_function
-+cwd_advance_fd (FTSOBJ *sp, int fd, bool chdir_down_one)
-+{
-+  int old = sp->fts_cwd_fd;
-+  fts_assert (old != fd || old == AT_FDCWD);
-+
-+  if (chdir_down_one)
-+    {
-+      /* Push "old" onto the ring.
-+         If the displaced file descriptor is non-negative, close it.  */
-+      int prev_fd_in_slot = i_ring_push (&sp->fts_fd_ring, old);
-+      fd_ring_print (sp, stderr, "post-push");
-+      if (0 <= prev_fd_in_slot)
-+        close (prev_fd_in_slot); /* ignore any close failure */
-+    }
-+  else if ( ! ISSET (FTS_NOCHDIR))
-+    {
-+      if (0 <= old)
-+        close (old); /* ignore any close failure */
-+    }
-+
-+  sp->fts_cwd_fd = fd;
-+}
-+
-+/* Restore the initial, pre-traversal, "working directory".
-+   In FTS_CWDFD mode, we merely call cwd_advance_fd, otherwise,
-+   we may actually change the working directory.
-+   Return 0 upon success. Upon failure, set errno and return nonzero.  */
-+static int
-+restore_initial_cwd (FTSOBJ *sp)
-+{
-+  int fail = FCHDIR (sp, ISSET (FTS_CWDFD) ? AT_FDCWD : sp->fts_rfd);
-+  fd_ring_clear (&(sp->fts_fd_ring));
-+  return fail;
-+}
-+
-+/* Open the directory DIR if possible, and return a file
-+   descriptor.  Return -1 and set errno on failure.  It doesn't matter
-+   whether the file descriptor has read or write access.  */
-+
-+static int
-+internal_function
-+diropen (FTSOBJ const *sp, char const *dir)
-+{
-+  int open_flags = (O_SEARCH | O_CLOEXEC | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
-+                    | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0));
-+
-+  int fd = (ISSET (FTS_CWDFD)
-+            ? openat (sp->fts_cwd_fd, dir, open_flags)
-+            : open (dir, open_flags));
-+  return fd;
-+}
-+
-+FTSOBJ *
-+FTS_OPEN (char * const *argv,
-+          register int options,
-+          int (*compar) (const FTSENTRY **, const FTSENTRY **))
-+{
-+        /* Options check: glibc added other flags after FTS_NAMEONLY and
-+	   FTS_STOP, and they are assumed to be private.  */
-+        if (options & ~FTS_OPTIONMASK
-+#if _LIBC
-+	    || options & (FTS_NAMEONLY | FTS_STOP)
-+#endif
-+	    ) {
-+                __set_errno (EINVAL);
-+                return (NULL);
-+        }
-+        if ((options & FTS_NOCHDIR) && (options & FTS_CWDFD)) {
-+                __set_errno (EINVAL);
-+                return (NULL);
-+        }
-+#if !_LIBC
-+        if ( ! (options & (FTS_LOGICAL | FTS_PHYSICAL))) {
-+                __set_errno (EINVAL);
-+                return (NULL);
-+        }
-+#else
-+	/* glibc historically falls to FTS_PHYSICAL if no FTS_PHYSICAL or
-+	   FTS_LOGICAL is specified.  */
-+        if (! (options & (FTS_PHYSICAL | FTS_LOGICAL)))
-+	  options |= FTS_PHYSICAL;
-+#endif
-+
-+        /* Allocate/initialize the stream */
-+        register FTSOBJ *sp = calloc (1, sizeof *sp);
-+        if (sp == NULL)
-+                return (NULL);
-+        sp->fts_compar = FTS_COMPAR_CAST(compar);
-+        sp->fts_options = options;
-+
-+        /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
-+        if (ISSET(FTS_LOGICAL)) {
-+                SET(FTS_NOCHDIR);
-+                CLR(FTS_CWDFD);
-+        }
-+
-+        /* Initialize fts_cwd_fd.  */
-+        sp->fts_cwd_fd = AT_FDCWD;
-+        if ( ISSET(FTS_CWDFD) && ! HAVE_OPENAT_SUPPORT)
-+          {
-+            /* While it isn't technically necessary to open "." this
-+               early, doing it here saves us the trouble of ensuring
-+               later (where it'd be messier) that "." can in fact
-+               be opened.  If not, revert to FTS_NOCHDIR mode.  */
-+            int fd = open (".", O_SEARCH | O_CLOEXEC);
-+            if (fd < 0)
-+              {
-+                /* Even if "." is unreadable, don't revert to FTS_NOCHDIR mode
-+                   on systems like Linux+PROC_FS, where our openat emulation
-+                   is good enough.  Note: on a system that emulates
-+                   openat via /proc, this technique can still fail, but
-+                   only in extreme conditions, e.g., when the working
-+                   directory cannot be saved (i.e. save_cwd fails) --
-+                   and that happens on Linux only when "." is unreadable
-+                   and the CWD would be longer than PATH_MAX.
-+                   FIXME: once Linux kernel openat support is well established,
-+                   replace the above open call and this entire if/else block
-+                   with the body of the if-block below.  */
-+                if ( openat_needs_fchdir ())
-+                  {
-+                    SET(FTS_NOCHDIR);
-+                    CLR(FTS_CWDFD);
-+                  }
-+              }
-+            else
-+              {
-+                close (fd);
-+              }
-+          }
-+
-+        /*
-+         * Start out with 1K of file name space, and enough, in any case,
-+         * to hold the user's file names.
-+         */
-+#ifndef MAXPATHLEN
-+# define MAXPATHLEN 1024
-+#endif
-+        {
-+          size_t maxarglen = fts_maxarglen(argv);
-+          if (! fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
-+                  goto mem1;
-+        }
-+
-+        /* Allocate/initialize root's parent. */
-+        FTSENTRY *parent = NULL;
-+        if (*argv != NULL) {
-+                if ((parent = fts_alloc(sp, "", 0)) == NULL)
-+                        goto mem2;
-+                parent->fts_level = FTS_ROOTPARENTLEVEL;
-+          }
-+
-+        /* The classic fts implementation would call fts_stat with
-+           a new entry for each iteration of the loop below.
-+           If the comparison function is not specified or if the
-+           FTS_DEFER_STAT option is in effect, don't stat any entry
-+           in this loop.  This is an attempt to minimize the interval
-+           between the initial stat/lstat/fstatat and the point at which
-+           a directory argument is first opened.  This matters for any
-+           directory command line argument that resides on a file system
-+           without genuine i-nodes.  If you specify FTS_DEFER_STAT along
-+           with a comparison function, that function must not access any
-+           data via the fts_statp pointer.  */
-+        bool defer_stat = (compar == NULL || ISSET(FTS_DEFER_STAT));
-+
-+        /* Allocate/initialize root(s). */
-+        register FTSENTRY *root;
-+        register size_t nitems;
-+        FTSENTRY *tmp = NULL;     /* pacify gcc */
-+        for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
-+                /* *Do* allow zero-length file names. */
-+                size_t len = strlen(*argv);
-+
-+                if ( ! (options & FTS_VERBATIM))
-+                  {
-+                    /* If there are two or more trailing slashes, trim all but one,
-+                       but don't change "//" to "/", and do map "///" to "/".  */
-+                    char const *v = *argv;
-+                    if (2 < len && v[len - 1] == '/')
-+                      while (1 < len && v[len - 2] == '/')
-+                        --len;
-+                  }
-+
-+                register FTSENTRY *p = fts_alloc(sp, *argv, len);
-+                if (p == NULL)
-+                        goto mem3;
-+                p->fts_level = FTS_ROOTLEVEL;
-+                p->fts_parent = parent;
-+                p->fts_accpath = p->fts_name;
-+                /* Even when defer_stat is true, be sure to stat the first
-+                   command line argument, since fts_read (at least with
-+                   FTS_XDEV) requires that.  */
-+                if (defer_stat && root != NULL) {
-+                        p->fts_info = FTS_NSOK;
-+                        fts_set_stat_required(p, true);
-+                } else {
-+                        p->fts_info = fts_stat(sp, p, false);
-+                }
-+
-+                /*
-+                 * If comparison routine supplied, traverse in sorted
-+                 * order; otherwise traverse in the order specified.
-+                 */
-+                if (compar) {
-+                        p->fts_link = root;
-+                        root = p;
-+                } else {
-+                        p->fts_link = NULL;
-+                        if (root == NULL)
-+                                tmp = root = p;
-+                        else {
-+                                tmp->fts_link = p;
-+                                tmp = p;
-+                        }
-+                }
-+        }
-+        if (compar && nitems > 1)
-+                root = fts_sort(sp, root, nitems);
-+
-+        /*
-+         * Allocate a dummy pointer and make fts_read think that we've just
-+         * finished the node before the root(s); set p->fts_info to FTS_INIT
-+         * so that everything about the "current" node is ignored.
-+         */
-+        if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
-+                goto mem3;
-+        sp->fts_cur->fts_link = root;
-+        sp->fts_cur->fts_info = FTS_INIT;
-+        sp->fts_cur->fts_level = 1;
-+        if (! setup_dir (sp))
-+                goto mem3;
-+
-+        /*
-+         * If using chdir(2), grab a file descriptor pointing to dot to ensure
-+         * that we can get back here; this could be avoided for some file names,
-+         * but almost certainly not worth the effort.  Slashes, symbolic links,
-+         * and ".." are all fairly nasty problems.  Note, if we can't get the
-+         * descriptor we run anyway, just more slowly.
-+         */
-+        if (!ISSET(FTS_NOCHDIR) && !ISSET(FTS_CWDFD)
-+            && (sp->fts_rfd = diropen (sp, ".")) < 0)
-+                SET(FTS_NOCHDIR);
-+
-+        i_ring_init (&sp->fts_fd_ring, -1);
-+        return (sp);
-+
-+mem3:   fts_lfree(root);
-+        free(FTSENT_WRAPPER(parent));
-+mem2:   free(sp->fts_path);
-+mem1:   free(sp);
-+        return (NULL);
-+}
-+
-+static void
-+internal_function
-+fts_load (FTSOBJ *sp, register FTSENTRY *p)
-+{
-+        /*
-+         * Load the stream structure for the next traversal.  Since we don't
-+         * actually enter the directory until after the preorder visit, set
-+         * the fts_accpath field specially so the chdir gets done to the right
-+         * place and the user can access the first node.  From fts_open it's
-+         * known that the file name will fit.
-+         */
-+        register size_t len = p->fts_pathlen = p->fts_namelen;
-+        memmove(sp->fts_path, p->fts_name, len + 1);
-+        register char *cp = strrchr(p->fts_name, '/');
-+        if (cp && (cp != p->fts_name || cp[1])) {
-+                len = strlen(++cp);
-+                memmove(p->fts_name, cp, len + 1);
-+                p->fts_namelen = len;
-+        }
-+        p->fts_accpath = p->fts_path = sp->fts_path;
-+}
-+
-+int
-+FTS_CLOSE (FTSOBJ *sp)
-+{
-+        /*
-+         * This still works if we haven't read anything -- the dummy structure
-+         * points to the root list, so we step through to the end of the root
-+         * list which has a valid parent pointer.
-+         */
-+        if (sp->fts_cur) {
-+                register FTSENTRY *p;
-+                for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
-+                        register FTSENTRY *freep = p;
-+                        p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
-+                        free(FTSENT_WRAPPER(freep));
-+                }
-+                free(FTSENT_WRAPPER(p));
-+        }
-+
-+        /* Free up child linked list, sort array, file name buffer. */
-+        if (sp->fts_child)
-+                fts_lfree(sp->fts_child);
-+        free(sp->fts_array);
-+        free(sp->fts_path);
-+
-+        int saved_errno = 0;
-+        if (ISSET(FTS_CWDFD))
-+          {
-+            if (0 <= sp->fts_cwd_fd)
-+              if (close (sp->fts_cwd_fd))
-+                saved_errno = errno;
-+          }
-+        else if (!ISSET(FTS_NOCHDIR))
-+          {
-+            /* Return to original directory, save errno if necessary. */
-+            if (fchdir(sp->fts_rfd))
-+              saved_errno = errno;
-+
-+            /* If close fails, record errno only if saved_errno is zero,
-+               so that we report the probably-more-meaningful fchdir errno.  */
-+            if (close (sp->fts_rfd))
-+              if (saved_errno == 0)
-+                saved_errno = errno;
-+          }
-+
-+        fd_ring_clear (&sp->fts_fd_ring);
-+
-+        if (sp->fts_leaf_optimization_works_ht)
-+          hash_free (sp->fts_leaf_optimization_works_ht);
-+
-+        free_dir (sp);
-+
-+        /* Free up the stream pointer. */
-+        free(sp);
-+
-+        /* Set errno and return. */
-+        if (saved_errno) {
-+                __set_errno (saved_errno);
-+                return (-1);
-+        }
-+
-+        return (0);
-+}
-+
-+/* Minimum link count of a traditional Unix directory.  When leaf
-+   optimization is OK and a directory's st_nlink == MIN_DIR_NLINK,
-+   then the directory has no subdirectories.  */
-+enum { MIN_DIR_NLINK = 2 };
-+
-+/* Whether leaf optimization is OK for a directory.  */
-+enum leaf_optimization
-+  {
-+    /* st_nlink is not reliable for this directory's subdirectories.  */
-+    NO_LEAF_OPTIMIZATION,
-+
-+    /* st_nlink == 2 means the directory lacks subdirectories.  */
-+    OK_LEAF_OPTIMIZATION
-+  };
-+
-+#if (defined __linux__ || defined __ANDROID__) \
-+  && HAVE_SYS_VFS_H && HAVE_FSTATFS && HAVE_STRUCT_STATFS_F_TYPE
-+
-+# include <sys/vfs.h>
-+
-+/* Linux-specific constants from coreutils' src/fs.h */
-+# define S_MAGIC_AFS 0x5346414F
-+# define S_MAGIC_CIFS 0xFF534D42
-+# define S_MAGIC_LUSTRE 0x0BD00BD0
-+# define S_MAGIC_NFS 0x6969
-+# define S_MAGIC_PROC 0x9FA0
-+# define S_MAGIC_TMPFS 0x1021994
-+
-+# ifdef HAVE___FSWORD_T
-+typedef __fsword_t fsword;
-+# else
-+typedef long int fsword;
-+# endif
-+
-+/* Map a stat.st_dev number to a file system type number f_ftype.  */
-+struct dev_type
-+{
-+  dev_t st_dev;
-+  fsword f_type;
-+};
-+
-+/* Use a tiny initial size.  If a traversal encounters more than
-+   a few devices, the cost of growing/rehashing this table will be
-+   rendered negligible by the number of inodes processed.  */
-+enum { DEV_TYPE_HT_INITIAL_SIZE = 13 };
-+
-+static size_t
-+dev_type_hash (void const *x, size_t table_size)
-+{
-+  struct dev_type const *ax = x;
-+  uintmax_t dev = ax->st_dev;
-+  return dev % table_size;
-+}
-+
-+static bool
-+dev_type_compare (void const *x, void const *y)
-+{
-+  struct dev_type const *ax = x;
-+  struct dev_type const *ay = y;
-+  return ax->st_dev == ay->st_dev;
-+}
-+
-+/* Return the file system type of P with file descriptor FD, or 0 if not known.
-+   If FD is negative, P's file descriptor is unavailable.
-+   Try to cache known values.  */
-+
-+static fsword
-+filesystem_type (FTSENTRY const *p, int fd)
-+{
-+  FTSOBJ *sp = FTSENT_FTS(p);
-+
-+  /* If we're not in CWDFD mode, don't bother with this optimization,
-+     since the caller is not serious about performance.  */
-+  if (!ISSET (FTS_CWDFD))
-+    return 0;
-+
-+  Hash_table *h = sp->fts_leaf_optimization_works_ht;
-+  if (! h)
-+    h = sp->fts_leaf_optimization_works_ht
-+      = hash_initialize (DEV_TYPE_HT_INITIAL_SIZE, NULL, dev_type_hash,
-+                         dev_type_compare, free);
-+
-+  if (h)
-+    {
-+      struct dev_type tmp;
-+      tmp.st_dev = p->fts_statp->st_dev;
-+      struct dev_type *ent = hash_lookup (h, &tmp);
-+      if (ent)
-+        return ent->f_type;
-+    }
-+
-+  /* Look-up failed.  Query directly and cache the result.  */
-+  struct STRUCT_STATFS fs_buf;
-+  if (fd < 0 || FSTATFS (fd, &fs_buf) != 0)
-+    return 0;
-+
-+  if (h)
-+    {
-+      struct dev_type *t2 = malloc (sizeof *t2);
-+      if (t2)
-+        {
-+          t2->st_dev = p->fts_statp->st_dev;
-+          t2->f_type = fs_buf.f_type;
-+
-+          struct dev_type *ent = hash_insert (h, t2);
-+          if (ent)
-+            fts_assert (ent == t2);
-+          else
-+            free (t2);
-+        }
-+    }
-+
-+  return fs_buf.f_type;
-+}
-+
-+/* Return true if sorting dirents on inode numbers is known to improve
-+   traversal performance for the directory P with descriptor DIR_FD.
-+   Return false otherwise.  When in doubt, return true.
-+   DIR_FD is negative if unavailable.  */
-+static bool
-+dirent_inode_sort_may_be_useful (FTSENTRY const *p, int dir_fd)
-+{
-+  /* Skip the sort only if we can determine efficiently
-+     that skipping it is the right thing to do.
-+     The cost of performing an unnecessary sort is negligible,
-+     while the cost of *not* performing it can be O(N^2) with
-+     a very large constant.  */
-+
-+  switch (filesystem_type (p, dir_fd))
-+    {
-+    case S_MAGIC_LUSTRE:
-+      /* On Lustre, sorting directory entries interferes with its ability to
-+         prefetch file metadata (via statahead).  This would make a command
-+         like 'du' around 9 times slower.  See
-+         <https://bugs.gnu.org/80106>.  */
-+    case S_MAGIC_CIFS:
-+    case S_MAGIC_NFS:
-+    case S_MAGIC_TMPFS:
-+      /* On a file system of any of these types, sorting
-+         is unnecessary, and hence wasteful.  */
-+      return false;
-+
-+    default:
-+      return true;
-+    }
-+}
-+
-+/* Given an FTS entry P for a directory with descriptor DIR_FD,
-+   return whether it is valid to apply leaf optimization.
-+   The optimization is valid if a directory's st_nlink value equal
-+   to MIN_DIR_NLINK means the directory has no subdirectories.
-+   DIR_FD is negative if unavailable.  */
-+static enum leaf_optimization
-+leaf_optimization (FTSENTRY const *p, int dir_fd)
-+{
-+  switch (filesystem_type (p, dir_fd))
-+    {
-+    case 0:
-+      /* Leaf optimization is unsafe if the file system type is unknown.  */
-+      FALLTHROUGH;
-+    case S_MAGIC_AFS:
-+      /* Although AFS mount points are not counted in st_nlink, they
-+         act like directories.  See <https://bugs.debian.org/143111>.  */
-+      FALLTHROUGH;
-+    case S_MAGIC_CIFS:
-+      /* Leaf optimization causes 'find' to abort.  See
-+         <https://lists.gnu.org/r/bug-gnulib/2018-04/msg00015.html>.  */
-+      FALLTHROUGH;
-+    case S_MAGIC_NFS:
-+      /* NFS provides usable dirent.d_type but not necessarily for all entries
-+         of large directories, so as per <https://bugzilla.redhat.com/1252549>
-+         NFS should return true.  However st_nlink values are not accurate on
-+         all implementations as per <https://bugzilla.redhat.com/1299169>.  */
-+      FALLTHROUGH;
-+    case S_MAGIC_PROC:
-+      /* Per <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=143111> /proc
-+         may have bogus stat.st_nlink values.  */
-+      return NO_LEAF_OPTIMIZATION;
-+
-+    default:
-+      return OK_LEAF_OPTIMIZATION;
-+    }
-+}
-+
-+#else
-+static bool
-+dirent_inode_sort_may_be_useful (_GL_UNUSED FTSENTRY const *p,
-+                                 _GL_UNUSED int dir_fd)
-+{
-+  return true;
-+}
-+static enum leaf_optimization
-+leaf_optimization (_GL_UNUSED FTSENTRY const *p, _GL_UNUSED int dir_fd)
-+{
-+  return NO_LEAF_OPTIMIZATION;
-+}
-+#endif
-+
-+/*
-+ * Special case of "/" at the end of the file name so that slashes aren't
-+ * appended which would cause file names to be written as "....//foo".
-+ */
-+#define NAPPEND(p)                                                      \
-+        (p->fts_path[p->fts_pathlen - 1] == '/'                         \
-+            ? p->fts_pathlen - 1 : p->fts_pathlen)
-+
-+FTSENTRY *
-+FTS_READ (FTSOBJ *sp)
-+{
-+        /* If finished or unrecoverable error, return NULL. */
-+        if (sp->fts_cur == NULL || ISSET(FTS_STOP))
-+                return (NULL);
-+
-+        /* Set current node pointer. */
-+        register FTSENTRY *p = sp->fts_cur;
-+
-+        /* Save and zero out user instructions. */
-+        register unsigned short int instr = p->fts_instr;
-+        p->fts_instr = FTS_NOINSTR;
-+
-+        /* Any type of file may be re-visited; re-stat and re-turn. */
-+        if (instr == FTS_AGAIN) {
-+                p->fts_info = fts_stat(sp, p, false);
-+                return (p);
-+        }
-+        Dprintf (("fts_read: p=%s\n",
-+                  p->fts_info == FTS_INIT ? "" : p->fts_path));
-+
-+        /*
-+         * Following a symlink -- SLNONE test allows application to see
-+         * SLNONE and recover.  If indirecting through a symlink, have
-+         * keep a pointer to current location.  If unable to get that
-+         * pointer, follow fails.
-+         */
-+        if (instr == FTS_FOLLOW &&
-+            (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
-+                p->fts_info = fts_stat(sp, p, true);
-+                if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
-+                        if ((p->fts_symfd = diropen (sp, ".")) < 0) {
-+                                p->fts_errno = errno;
-+                                p->fts_info = FTS_ERR;
-+                        } else
-+                                p->fts_flags |= FTS_SYMFOLLOW;
-+                }
-+                goto check_for_dir;
-+        }
-+
-+        /* Directory in pre-order. */
-+        if (p->fts_info == FTS_D) {
-+                /* If skipped or crossed mount point, do post-order visit. */
-+                if (instr == FTS_SKIP ||
-+                    (ISSET(FTS_XDEV) && p->fts_statp->st_dev != sp->fts_dev)) {
-+                        if (p->fts_flags & FTS_SYMFOLLOW)
-+                                (void)close(p->fts_symfd);
-+                        if (sp->fts_child) {
-+                                fts_lfree(sp->fts_child);
-+                                sp->fts_child = NULL;
-+                        }
-+                        p->fts_info = FTS_DP;
-+                        LEAVE_DIR (sp, p, "1");
-+                        return (p);
-+                }
-+
-+                /* Rebuild if only read the names and now traversing. */
-+                if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
-+                        CLR(FTS_NAMEONLY);
-+                        fts_lfree(sp->fts_child);
-+                        sp->fts_child = NULL;
-+                }
-+
-+                /*
-+                 * Cd to the subdirectory.
-+                 *
-+                 * If have already read and now fail to chdir, whack the list
-+                 * to make the names come out right, and set the parent errno
-+                 * so the application will eventually get an error condition.
-+                 * Set the FTS_DONTCHDIR flag so that when we logically change
-+                 * directories back to the parent we don't do a chdir.
-+                 *
-+                 * If haven't read do so.  If the read fails, fts_build sets
-+                 * FTS_STOP or the fts_info field of the node.
-+                 */
-+                if (sp->fts_child != NULL) {
-+                        if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
-+                                p->fts_errno = errno;
-+                                p->fts_flags |= FTS_DONTCHDIR;
-+                                for (p = sp->fts_child; p != NULL;
-+                                     p = p->fts_link)
-+                                        p->fts_accpath =
-+                                            p->fts_parent->fts_accpath;
-+                        }
-+                } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
-+                        if (ISSET(FTS_STOP))
-+                                return (NULL);
-+                        /* If fts_build's call to fts_safe_changedir failed
-+                           because it was not able to fchdir into a
-+                           subdirectory, tell the caller.  */
-+                        if (p->fts_errno && p->fts_info != FTS_DNR)
-+                                p->fts_info = FTS_ERR;
-+                        LEAVE_DIR (sp, p, "2");
-+                        return (p);
-+                }
-+                p = sp->fts_child;
-+                sp->fts_child = NULL;
-+                goto name;
-+        }
-+
-+        /* Move to the next node on this level. */
-+next: ;
-+        register FTSENTRY *tmp = p;
-+
-+        /* If we have so many directory entries that we're reading them
-+           in batches, and we've reached the end of the current batch,
-+           read in a new batch.  */
-+        if (p->fts_link == NULL && FTSENT_DIRP(p->fts_parent))
-+          {
-+            p = tmp->fts_parent;
-+            sp->fts_cur = p;
-+            sp->fts_path[p->fts_pathlen] = '\0';
-+
-+            if ((p = fts_build (sp, BREAD)) == NULL)
-+              {
-+                if (ISSET(FTS_STOP))
-+                  return NULL;
-+                goto cd_dot_dot;
-+              }
-+
-+            free(FTSENT_WRAPPER(tmp));
-+            goto name;
-+          }
-+
-+        if ((p = p->fts_link) != NULL) {
-+                sp->fts_cur = p;
-+                free(FTSENT_WRAPPER(tmp));
-+
-+                /*
-+                 * If reached the top, return to the original directory (or
-+                 * the root of the tree), and load the file names for the next
-+                 * root.
-+                 */
-+                if (p->fts_level == FTS_ROOTLEVEL) {
-+                        if (restore_initial_cwd(sp)) {
-+                                SET(FTS_STOP);
-+                                return (NULL);
-+                        }
-+                        free_dir(sp);
-+                        fts_load(sp, p);
-+                        if (! setup_dir(sp)) {
-+                                free_dir(sp);
-+                                return (NULL);
-+                        }
-+                        goto check_for_dir;
-+                }
-+
-+                /*
-+                 * User may have called fts_set on the node.  If skipped,
-+                 * ignore.  If followed, get a file descriptor so we can
-+                 * get back if necessary.
-+                 */
-+                if (p->fts_instr == FTS_SKIP)
-+                        goto next;
-+                if (p->fts_instr == FTS_FOLLOW) {
-+                        p->fts_info = fts_stat(sp, p, true);
-+                        if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
-+                                if ((p->fts_symfd = diropen (sp, ".")) < 0) {
-+                                        p->fts_errno = errno;
-+                                        p->fts_info = FTS_ERR;
-+                                } else
-+                                        p->fts_flags |= FTS_SYMFOLLOW;
-+                        }
-+                        p->fts_instr = FTS_NOINSTR;
-+                }
-+
-+name:           {
-+                  register char *t = sp->fts_path + NAPPEND(p->fts_parent);
-+                  *t++ = '/';
-+                  memmove(t, p->fts_name, p->fts_namelen + 1);
-+                }
-+check_for_dir:
-+                sp->fts_cur = p;
-+                if (p->fts_info == FTS_NSOK)
-+                  {
-+                    if (p->fts_statp->st_size == FTS_STAT_REQUIRED)
-+                      p->fts_info = fts_stat(sp, p, false);
-+                    else
-+                      fts_assert (p->fts_statp->st_size == FTS_NO_STAT_REQUIRED);
-+                  }
-+
-+                /* Skip files with different device numbers when FTS_MOUNT
-+                   is set.  */
-+                if (ISSET (FTS_MOUNT) && p->fts_info != FTS_NS &&
-+                    p->fts_level != FTS_ROOTLEVEL &&
-+                    p->fts_statp->st_dev != sp->fts_dev)
-+                      goto next;
-+
-+                if (p->fts_info == FTS_D)
-+                  {
-+                    /* Now that P->fts_statp is guaranteed to be valid, if
-+                       this is a command-line directory, record its device
-+                       number, to be used for FTS_MOUNT and FTS_XDEV.  */
-+                    if (p->fts_level == FTS_ROOTLEVEL)
-+                      sp->fts_dev = p->fts_statp->st_dev;
-+                    Dprintf (("  entering: %s\n", p->fts_path));
-+                    if (! enter_dir (sp, p))
-+                      return NULL;
-+                  }
-+                return p;
-+        }
-+cd_dot_dot:
-+
-+        /* Move up to the parent node. */
-+        p = tmp->fts_parent;
-+        sp->fts_cur = p;
-+        free(FTSENT_WRAPPER(tmp));
-+
-+        if (p->fts_level == FTS_ROOTPARENTLEVEL) {
-+                /*
-+                 * Done; free everything up and set errno to 0 so the user
-+                 * can distinguish between error and EOF.
-+                 */
-+                free(FTSENT_WRAPPER(p));
-+                __set_errno (0);
-+                return (sp->fts_cur = NULL);
-+        }
-+
-+        fts_assert (p->fts_info != FTS_NSOK);
-+
-+        /* NUL terminate the file name.  */
-+        sp->fts_path[p->fts_pathlen] = '\0';
-+
-+        /*
-+         * Return to the parent directory.  If at a root node, restore
-+         * the initial working directory.  If we came through a symlink,
-+         * go back through the file descriptor.  Otherwise, move up
-+         * one level, via "..".
-+         */
-+        if (p->fts_level == FTS_ROOTLEVEL) {
-+                if (restore_initial_cwd(sp)) {
-+                        p->fts_errno = errno;
-+                        SET(FTS_STOP);
-+                }
-+        } else if (p->fts_flags & FTS_SYMFOLLOW) {
-+                if (FCHDIR(sp, p->fts_symfd)) {
-+                        p->fts_errno = errno;
-+                        SET(FTS_STOP);
-+                }
-+                (void)close(p->fts_symfd);
-+        } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
-+                   fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
-+                p->fts_errno = errno;
-+                SET(FTS_STOP);
-+        }
-+
-+        /* If the directory causes a cycle, preserve the FTS_DC flag and keep
-+           the corresponding dev/ino pair in the hash table.  It is going to be
-+           removed when leaving the original directory.  */
-+        if (p->fts_info != FTS_DC) {
-+                p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
-+                if (p->fts_errno == 0)
-+                        LEAVE_DIR (sp, p, "3");
-+        }
-+        return ISSET(FTS_STOP) ? NULL : p;
-+}
-+
-+/*
-+ * Fts_set takes the stream as an argument although it's not used in this
-+ * implementation; it would be necessary if anyone wanted to add global
-+ * semantics to fts using fts_set.  An error return is allowed for similar
-+ * reasons.
-+ */
-+/* ARGSUSED */
-+int
-+FTS_SET (_GL_UNUSED FTSOBJ *sp, FTSENTRY *p, int instr)
-+{
-+        if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
-+            instr != FTS_NOINSTR && instr != FTS_SKIP) {
-+                __set_errno (EINVAL);
-+                return (1);
-+        }
-+        p->fts_instr = instr;
-+        return (0);
-+}
-+
-+FTSENTRY *
-+FTS_CHILDREN (FTSOBJ *sp, int instr)
-+{
-+        if (instr != 0 && instr != FTS_NAMEONLY) {
-+                __set_errno (EINVAL);
-+                return (NULL);
-+        }
-+
-+        /* Set current node pointer. */
-+        register FTSENTRY *p = sp->fts_cur;
-+
-+        /*
-+         * Errno set to 0 so user can distinguish empty directory from
-+         * an error.
-+         */
-+        __set_errno (0);
-+
-+        /* Fatal errors stop here. */
-+        if (ISSET(FTS_STOP))
-+                return (NULL);
-+
-+        /* Return logical hierarchy of user's arguments. */
-+        if (p->fts_info == FTS_INIT)
-+                return (p->fts_link);
-+
-+        /*
-+         * If not a directory being visited in pre-order, stop here.  Could
-+         * allow FTS_DNR, assuming the user has fixed the problem, but the
-+         * same effect is available with FTS_AGAIN.
-+         */
-+        if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
-+                return (NULL);
-+
-+        /* Free up any previous child list. */
-+        if (sp->fts_child != NULL)
-+                fts_lfree(sp->fts_child);
-+
-+        if (instr == FTS_NAMEONLY) {
-+                SET(FTS_NAMEONLY);
-+                instr = BNAMES;
-+        } else
-+                instr = BCHILD;
-+
-+        /*
-+         * If using chdir on a relative file name and called BEFORE fts_read
-+         * does its chdir to the root of a traversal, we can lose -- we need to
-+         * chdir into the subdirectory, and we don't know where the current
-+         * directory is, so we can't get back so that the upcoming chdir by
-+         * fts_read will work.
-+         */
-+        if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
-+            ISSET(FTS_NOCHDIR))
-+                return (sp->fts_child = fts_build(sp, instr));
-+
-+        int fd = diropen (sp, ".");
-+        if (fd < 0)
-+                return (sp->fts_child = NULL);
-+        sp->fts_child = fts_build(sp, instr);
-+        if (ISSET(FTS_CWDFD))
-+          {
-+            cwd_advance_fd (sp, fd, true);
-+          }
-+        else
-+          {
-+            if (fchdir(fd))
-+              {
-+                int saved_errno = errno;
-+                close (fd);
-+                __set_errno (saved_errno);
-+                return NULL;
-+              }
-+            close (fd);
-+          }
-+        return (sp->fts_child);
-+}
-+
-+/* A comparison function to sort on increasing inode number.
-+   For some file system types, sorting either way makes a huge
-+   performance difference for a directory with very many entries,
-+   but sorting on increasing values is slightly better than sorting
-+   on decreasing values.  The difference is in the 5% range.  */
-+static int
-+fts_compare_ino (FTSENTRY const **a, FTSENTRY const **b)
-+{
-+  return _GL_CMP (a[0]->fts_statp->st_ino, b[0]->fts_statp->st_ino);
-+}
-+
-+/* Map the dirent.d_type value, DTYPE, to the corresponding stat.st_mode
-+   S_IF* bit and set ST.st_mode, thus clearing all other bits in that field.  */
-+static void
-+set_stat_type (struct STRUCT_STAT *st, unsigned int dtype)
-+{
-+  mode_t type;
-+  switch (dtype)
-+    {
-+    case DT_BLK:
-+      type = S_IFBLK;
-+      break;
-+    case DT_CHR:
-+      type = S_IFCHR;
-+      break;
-+    case DT_DIR:
-+      type = S_IFDIR;
-+      break;
-+    case DT_FIFO:
-+      type = S_IFIFO;
-+      break;
-+    case DT_LNK:
-+      type = S_IFLNK;
-+      break;
-+    case DT_REG:
-+      type = S_IFREG;
-+      break;
-+    case DT_SOCK:
-+      type = S_IFSOCK;
-+      break;
-+    default:
-+      type = 0;
-+    }
-+  st->st_mode = type;
-+}
-+
-+#define closedir_and_clear(dirp)                \
-+  do                                            \
-+    {                                           \
-+      closedir (dirp);                          \
-+      dirp = NULL;                              \
-+    }                                           \
-+  while (0)
-+
-+#define fts_opendir(file, Pdir_fd)                              \
-+        OPENDIRAT((! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD)     \
-+                   ? sp->fts_cwd_fd : AT_FDCWD),                \
-+                  file,                                         \
-+                  (((ISSET(FTS_PHYSICAL)                        \
-+                     && ! (ISSET(FTS_COMFOLLOW)                 \
-+                           && cur->fts_level == FTS_ROOTLEVEL)) \
-+                    ? O_NOFOLLOW : 0)),                         \
-+                  Pdir_fd)
-+
-+/*
-+ * This is the tricky part -- do not casually change *anything* in here.  The
-+ * idea is to build the linked list of entries that are used by fts_children
-+ * and fts_read.  There are lots of special cases.
-+ *
-+ * The real slowdown in walking the tree is the stat calls.  If FTS_NOSTAT is
-+ * set and it's a physical walk (so that symbolic links can't be directories),
-+ * we can do things quickly.  First, if it's a 4.4BSD file system, the type
-+ * of the file is in the directory entry.  Otherwise, we assume that the number
-+ * of subdirectories in a node is equal to the number of links to the parent.
-+ * The former skips all stat calls.  The latter skips stat calls in any leaf
-+ * directories and for any files after the subdirectories in the directory have
-+ * been found, cutting the stat calls by about 2/3.
-+ */
-+static FTSENTRY *
-+internal_function
-+fts_build (register FTSOBJ *sp, int type)
-+{
-+        FTSENTRY *cur = sp->fts_cur;
-+        bool continue_readdir = !!FTSENT_DIRP(cur);
-+
-+        /* When cur->fts_dirp is non-NULL, that means we should
-+           continue calling readdir on that existing DIR* pointer
-+           rather than opening a new one.  */
-+        int dir_fd;
-+        if (continue_readdir)
-+          {
-+            DIR *dp = FTSENT_DIRP(cur);
-+            dir_fd = dirfd (dp);
-+            if (dir_fd < 0)
-+              {
-+                int dirfd_errno = errno;
-+                closedir_and_clear (FTSENT_DIRP(cur));
-+                if (type == BREAD)
-+                  {
-+                    cur->fts_info = FTS_DNR;
-+                    cur->fts_errno = dirfd_errno;
-+                  }
-+                return NULL;
-+              }
-+          }
-+        else
-+          {
-+            /* Open the directory for reading.  If this fails, we're done.
-+               If being called from fts_read, set the fts_info field. */
-+            if ((FTSENT_DIRP (cur) = fts_opendir(cur->fts_accpath, &dir_fd)) == NULL)
-+              {
-+                if (type == BREAD)
-+                  {
-+                    cur->fts_info = FTS_DNR;
-+                    cur->fts_errno = errno;
-+                  }
-+                return NULL;
-+              }
-+            /* Rather than calling fts_stat for each and every entry encountered
-+               in the readdir loop (below), stat each directory only right after
-+               opening it.  */
-+            bool stat_optimization = cur->fts_info == FTS_NSOK;
-+
-+            if (stat_optimization
-+                /* Also read the stat info again after opening a directory to
-+                   reveal eventual changes caused by a submount triggered by
-+                   the traversal.  But do it only for utilities which use
-+                   FTS_TIGHT_CYCLE_CHECK.  Therefore, only find and du
-+                   benefit/suffer from this feature for now.  */
-+                || ISSET (FTS_TIGHT_CYCLE_CHECK))
-+              {
-+                if (!stat_optimization)
-+                  LEAVE_DIR (sp, cur, "4");
-+                if (FSTAT (dir_fd, cur->fts_statp) != 0)
-+                  {
-+                    int fstat_errno = errno;
-+                    closedir_and_clear (FTSENT_DIRP(cur));
-+                    if (type == BREAD)
-+                      {
-+                        cur->fts_errno = fstat_errno;
-+                        cur->fts_info = FTS_NS;
-+                      }
-+                    __set_errno (fstat_errno);
-+                    return NULL;
-+                  }
-+                if (stat_optimization)
-+                  cur->fts_info = FTS_D;
-+                else if (! enter_dir (sp, cur))
-+                  {
-+                    int saved_errno = errno;
-+                    closedir_and_clear (FTSENT_DIRP(cur));
-+                    __set_errno (saved_errno);
-+                    return NULL;
-+                  }
-+              }
-+          }
-+
-+        /* Maximum number of readdir entries to read at one time.  This
-+           limitation is to avoid reading millions of entries into memory
-+           at once.  When an fts_compar function is specified, we have no
-+           choice: we must read all entries into memory before calling that
-+           function.  But when no such function is specified, we can read
-+           entries in batches that are large enough to help us with inode-
-+           sorting, yet not so large that we risk exhausting memory.  */
-+        size_t max_entries = sp->fts_compar ? SIZE_MAX : FTS_MAX_READDIR_ENTRIES;
-+
-+        /*
-+         * If we're going to need to stat anything or we want to descend
-+         * and stay in the directory, chdir.  If this fails we keep going,
-+         * but set a flag so we don't chdir after the post-order visit.
-+         * We won't be able to stat anything, but we can still return the
-+         * names themselves.  Note, that since fts_read won't be able to
-+         * chdir into the directory, it will have to return different file
-+         * names than before, i.e. "a/b" instead of "b".  Since the node
-+         * has already been visited in pre-order, have to wait until the
-+         * post-order visit to return the error.  There is a special case
-+         * here, if there was nothing to stat then it's not an error to
-+         * not be able to stat.  This is all fairly nasty.  If a program
-+         * needed sorted entries or stat information, they had better be
-+         * checking FTS_NS on the returned nodes.
-+         */
-+        bool descend;
-+        if (continue_readdir)
-+          {
-+            /* When resuming a short readdir run, we already have
-+               the required dirp and dir_fd.  */
-+            descend = true;
-+          }
-+        else
-+          {
-+            /* Try to descend unless it is a names-only fts_children,
-+               or the directory is known to lack subdirectories.  */
-+            descend = (type != BNAMES
-+                       && ! (ISSET (FTS_NOSTAT) && ISSET (FTS_PHYSICAL)
-+                             && ! ISSET (FTS_SEEDOT)
-+                             && cur->fts_statp->st_nlink == MIN_DIR_NLINK
-+                             && (leaf_optimization (cur, dir_fd)
-+                                 != NO_LEAF_OPTIMIZATION)));
-+            if (descend || type == BREAD)
-+              {
-+                if (ISSET(FTS_CWDFD))
-+                  dir_fd = fcntl (dir_fd, F_DUPFD_CLOEXEC, STDERR_FILENO + 1);
-+                if (dir_fd < 0 || fts_safe_changedir(sp, cur, dir_fd, NULL)) {
-+                        if (descend && type == BREAD)
-+                                cur->fts_errno = errno;
-+                        cur->fts_flags |= FTS_DONTCHDIR;
-+                        descend = false;
-+                        closedir_and_clear(FTSENT_DIRP(cur));
-+                        if (ISSET(FTS_CWDFD) && 0 <= dir_fd)
-+                                close (dir_fd);
-+                        FTSENT_DIRP(cur) = NULL;
-+                } else
-+                        descend = true;
-+              }
-+          }
-+
-+        /*
-+         * Figure out the max file name length that can be stored in the
-+         * current buffer -- the inner loop allocates more space as necessary.
-+         * We really wouldn't have to do the maxlen calculations here, we
-+         * could do them in fts_read before returning the name, but it's a
-+         * lot easier here since the length is part of the dirent structure.
-+         *
-+         * If not changing directories set a pointer so that can just append
-+         * each new component into the file name.
-+         */
-+        size_t len = NAPPEND(cur);
-+        char *cp;
-+        if (ISSET(FTS_NOCHDIR)) {
-+                cp = sp->fts_path + len;
-+                *cp++ = '/';
-+        } else {
-+                /* GCC, you're too verbose. */
-+                cp = NULL;
-+        }
-+        len++;
-+        size_t maxlen = sp->fts_pathlen - len;
-+
-+        ptrdiff_t level = cur->fts_level + 1;
-+
-+        /* Read the directory, attaching each entry to the "link" pointer. */
-+        bool doadjust = false;
-+        register FTSENTRY *head = NULL;
-+        FTSENTRY *tail = NULL;
-+        register size_t nitems = 0;
-+        bool sort_by_inode = false;
-+        while (FTSENT_DIRP(cur)) {
-+                __set_errno (0);
-+                struct dirent *dp = readdir(FTSENT_DIRP(cur));
-+                if (dp == NULL) {
-+                        /* Some readdir()s do not absorb ENOENT (dir
-+                           deleted but open).  This bug was fixed in
-+                           glibc 2.3 (2002).  */
-+#if ! (2 < __GLIBC__ + (3 <= __GLIBC_MINOR__))
-+                        if (errno == ENOENT)
-+                          errno = 0;
-+#endif
-+                        if (errno) {
-+                                cur->fts_errno = errno;
-+                                /* If we've not read any items yet, treat
-+                                   the error as if we can't access the dir.  */
-+                                cur->fts_info = (continue_readdir || nitems)
-+                                                ? FTS_ERR : FTS_DNR;
-+                        }
-+                        closedir_and_clear(FTSENT_DIRP(cur));
-+                        break;
-+                }
-+                if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
-+                        continue;
-+
-+                size_t d_namelen = _D_EXACT_NAMLEN (dp);
-+                register FTSENTRY *p = fts_alloc (sp, dp->d_name, d_namelen);
-+                if (!p)
-+                        goto mem1;
-+                if (d_namelen >= maxlen) {
-+                        /* include space for NUL */
-+                        uintptr_t oldaddr = (uintptr_t) sp->fts_path;
-+                        if (! fts_palloc(sp, d_namelen + len + 1)) {
-+                                /*
-+                                 * No more memory.  Save
-+                                 * errno, free up the current structure and the
-+                                 * structures already allocated.
-+                                 */
-+mem1: ;
-+                                int saved_errno = errno;
-+                                free(FTSENT_WRAPPER(p));
-+                                fts_lfree(head);
-+                                closedir_and_clear(FTSENT_DIRP(cur));
-+                                cur->fts_info = FTS_ERR;
-+                                SET(FTS_STOP);
-+                                __set_errno (saved_errno);
-+                                return (NULL);
-+                        }
-+                        /* Did realloc() change the pointer? */
-+                        if (oldaddr != (uintptr_t) sp->fts_path) {
-+                                doadjust = true;
-+                                if (ISSET(FTS_NOCHDIR))
-+                                        cp = sp->fts_path + len;
-+                        }
-+                        maxlen = sp->fts_pathlen - len;
-+                }
-+
-+                size_t new_len = len + d_namelen;
-+                if (new_len < len) {
-+                        /*
-+                         * In the unlikely event that we would end up
-+                         * with a file name longer than SIZE_MAX, free up
-+                         * the current structure and the structures already
-+                         * allocated, then error out with ENAMETOOLONG.
-+                         */
-+                        free(FTSENT_WRAPPER(p));
-+                        fts_lfree(head);
-+                        closedir_and_clear(FTSENT_DIRP(cur));
-+                        cur->fts_info = FTS_ERR;
-+                        SET(FTS_STOP);
-+                        __set_errno (ENAMETOOLONG);
-+                        return (NULL);
-+                }
-+                p->fts_level = level;
-+                p->fts_parent = sp->fts_cur;
-+                p->fts_pathlen = new_len;
-+
-+                /* Store dirent.d_ino, in case we need to sort
-+                   entries before processing them.  */
-+                p->fts_statp->st_ino = D_INO (dp);
-+
-+                /* Build a file name for fts_stat to stat. */
-+                if (ISSET(FTS_NOCHDIR)) {
-+                        p->fts_accpath = p->fts_path;
-+                        memmove(cp, p->fts_name, p->fts_namelen + 1);
-+                } else
-+                        p->fts_accpath = p->fts_name;
-+
-+                if (sp->fts_compar == NULL || ISSET(FTS_DEFER_STAT)) {
-+                        /* Record what fts_read will have to do with this
-+                           entry. In many cases, it will simply fts_stat it,
-+                           but we can take advantage of any d_type information
-+                           to optimize away the unnecessary stat calls.  I.e.,
-+                           if FTS_NOSTAT is in effect, we don't need device
-+                           numbers unconditionally (FTS_MOUNT) and we're not
-+                           following symlinks (FTS_PHYSICAL) and d_type
-+                           indicates this is *not* a directory, then we won't
-+                           have to stat it  at all.  If it *is* a directory,
-+                           then (currently) we stat it regardless, in order to
-+                           get device and inode numbers.  Some day we might
-+                           optimize that away, too, for directories where
-+                           d_ino is known to be valid.  */
-+                        bool skip_stat = (ISSET(FTS_NOSTAT)
-+                                          && DT_IS_KNOWN(dp)
-+                                          && ! DT_MUST_BE(dp, DT_DIR)
-+                                          && (ISSET(FTS_PHYSICAL)
-+                                              || ! DT_MUST_BE(dp, DT_LNK))
-+                                          && ! ISSET(FTS_MOUNT));
-+                        p->fts_info = FTS_NSOK;
-+                        /* Propagate dirent.d_type information back
-+                           to caller, when possible.  */
-+                        set_stat_type (p->fts_statp, D_TYPE (dp));
-+                        fts_set_stat_required(p, !skip_stat);
-+                } else {
-+                        p->fts_info = fts_stat(sp, p, false);
-+                }
-+
-+                /* We walk in directory order so "ls -f" doesn't get upset. */
-+                p->fts_link = NULL;
-+                if (head == NULL)
-+                        head = tail = p;
-+                else {
-+                        tail->fts_link = p;
-+                        tail = p;
-+                }
-+
-+                /* If there are many entries, no sorting function has been
-+                   specified, and this file system is of a type that may be
-+                   slow with a large number of entries, arrange to sort the
-+                   directory entries on increasing inode numbers.
-+
-+                   The NITEMS comparison uses ==, not >, because the test
-+                   needs to be tried at most once once, and NITEMS will exceed
-+                   the threshold after it is incremented below.  */
-+                if (nitems == _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
-+                    && !sp->fts_compar)
-+                  sort_by_inode = dirent_inode_sort_may_be_useful (cur, dir_fd);
-+
-+                ++nitems;
-+                if (max_entries <= nitems) {
-+                        /* When there are too many dir entries, leave
-+                           fts_dirp open, so that a subsequent fts_read
-+                           can take up where we leave off.  */
-+                        break;
-+                }
-+        }
-+
-+        /*
-+         * If realloc() changed the address of the file name, adjust the
-+         * addresses for the rest of the tree and the dir list.
-+         */
-+        if (doadjust)
-+                fts_padjust(sp, head);
-+
-+        /*
-+         * If not changing directories, reset the file name back to original
-+         * state.
-+         */
-+        if (ISSET(FTS_NOCHDIR)) {
-+                if (len == sp->fts_pathlen || nitems == 0)
-+                        --cp;
-+                *cp = '\0';
-+        }
-+
-+        /*
-+         * If descended after called from fts_children or after called from
-+         * fts_read and nothing found, get back.  At the root level we use
-+         * the saved fd; if one of fts_open()'s arguments is a relative name
-+         * to an empty directory, we wind up here with no other way back.  If
-+         * can't get back, we're done.
-+         */
-+        if (!continue_readdir && descend && (type == BCHILD || !nitems) &&
-+            (cur->fts_level == FTS_ROOTLEVEL
-+             ? restore_initial_cwd(sp)
-+             : fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
-+                cur->fts_info = FTS_ERR;
-+                SET(FTS_STOP);
-+                fts_lfree(head);
-+                return (NULL);
-+        }
-+
-+        /* If didn't find anything, return NULL. */
-+        if (!nitems) {
-+                if (type == BREAD
-+                    && cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR)
-+                        cur->fts_info = FTS_DP;
-+                fts_lfree(head);
-+                return (NULL);
-+        }
-+
-+        if (sort_by_inode) {
-+                sp->fts_compar = FTS_COMPAR_CAST (fts_compare_ino);
-+                head = fts_sort (sp, head, nitems);
-+                sp->fts_compar = NULL;
-+        }
-+
-+        /* Sort the entries. */
-+        if (sp->fts_compar && nitems > 1)
-+                head = fts_sort(sp, head, nitems);
-+        return (head);
-+}
-+
-+#if GNULIB_FTS_DEBUG
-+
-+struct devino {
-+  intmax_t dev, ino;
-+};
-+#define PRINT_DEVINO "(%jd,%jd)"
-+
-+static struct devino
-+getdevino (int fd)
-+{
-+  struct STRUCT_STAT st;
-+  return (fd == AT_FDCWD
-+          ? (struct devino) { -1, 0 }
-+          : FSTAT (fd, &st) == 0
-+          ? (struct devino) { st.st_dev, st.st_ino }
-+          : (struct devino) { -1, errno });
-+}
-+
-+/* Walk ->fts_parent links starting at E_CURR, until the root of the
-+   current hierarchy.  There should be a directory with dev/inode
-+   matching those of AD.  If not, print a lot of diagnostics.  */
-+static void
-+find_matching_ancestor (FTSENTRY const *e_curr, struct Active_dir const *ad)
-+{
-+  for (FTSENTRY const *ent = e_curr;
-+       ent->fts_level >= FTS_ROOTLEVEL;
-+       ent = ent->fts_parent)
-+    {
-+      if (ad->ino == ent->fts_statp->st_ino
-+          && ad->dev == ent->fts_statp->st_dev)
-+        return;
-+    }
-+  printf ("ERROR: tree dir, %s, not active\n", ad->fts_ent->fts_accpath);
-+  printf ("active dirs:\n");
-+  for (FTSENTRY const *ent = e_curr;
-+       ent->fts_level >= FTS_ROOTLEVEL;
-+       ent = ent->fts_parent)
-+    printf ("  %s(%"PRIuMAX"/%"PRIuMAX") to %s(%"PRIuMAX"/%"PRIuMAX")...\n",
-+            ad->fts_ent->fts_accpath,
-+            (uintmax_t) ad->dev,
-+            (uintmax_t) ad->ino,
-+            ent->fts_accpath,
-+            (uintmax_t) ent->fts_statp->st_dev,
-+            (uintmax_t) ent->fts_statp->st_ino);
-+}
-+
-+void
-+fts_cross_check (FTSOBJ const *sp)
-+{
-+  if ( ! ISSET (FTS_TIGHT_CYCLE_CHECK))
-+    return;
-+
-+  FTSENTRY const *ent = sp->fts_cur;
-+
-+  Dprintf (("fts-cross-check cur=%s\n", ent->fts_path));
-+  /* Make sure every parent dir is in the tree.  */
-+  for (FTSENTRY const *t = ent->fts_parent;
-+       t->fts_level >= FTS_ROOTLEVEL;
-+       t = t->fts_parent)
-+    {
-+      struct Active_dir ad;
-+      ad.ino = t->fts_statp->st_ino;
-+      ad.dev = t->fts_statp->st_dev;
-+      if ( ! hash_lookup (sp->fts_cycle.ht, &ad))
-+        printf ("ERROR: active dir, %s, not in tree\n", t->fts_path);
-+    }
-+
-+  /* Make sure every dir in the tree is an active dir.
-+     But ENT is not necessarily a directory.  If so, just skip this part. */
-+  if (ent->fts_parent->fts_level >= FTS_ROOTLEVEL
-+      && (ent->fts_info == FTS_DP
-+          || ent->fts_info == FTS_D))
-+    for (struct Active_dir *ad = hash_get_first (sp->fts_cycle.ht);
-+         ad != NULL;
-+         ad = hash_get_next (sp->fts_cycle.ht, ad))
-+      {
-+        find_matching_ancestor (ent, ad);
-+      }
-+}
-+
-+static bool
-+same_fd (int fd1, int fd2)
-+{
-+  struct STRUCT_STAT sb1, sb2;
-+  return (FSTAT (fd1, &sb1) == 0
-+          && FSTAT (fd2, &sb2) == 0
-+          && psame_inode (&sb1, &sb2));
-+}
-+
-+static void
-+fd_ring_print (FTSOBJ const *sp, FILE *stream, char const *msg)
-+{
-+  if (!fts_debug)
-+    return;
-+  I_ring const *fd_ring = &sp->fts_fd_ring;
-+  struct devino cwd = getdevino (sp->fts_cwd_fd);
-+  fprintf (stream, "=== %s ========== "PRINT_DEVINO"\n", msg, cwd.dev, cwd.ino);
-+  if (i_ring_empty (fd_ring))
-+    return;
-+
-+  unsigned int i = fd_ring->ir_front;
-+  while (true)
-+    {
-+      int fd = fd_ring->ir_data[i];
-+      if (fd < 0)
-+        fprintf (stream, "%u: %d:\n", i, fd);
-+      else
-+        {
-+          struct devino wd = getdevino (fd);
-+          fprintf (stream, "%u: %d: "PRINT_DEVINO"\n", i, fd, wd.dev, wd.ino);
-+        }
-+      if (i == fd_ring->ir_back)
-+        break;
-+      i = (i + I_RING_SIZE - 1) % I_RING_SIZE;
-+    }
-+}
-+
-+/* Ensure that each file descriptor on the fd_ring matches a
-+   parent, grandparent, etc. of the current working directory.  */
-+static void
-+fd_ring_check (FTSOBJ const *sp)
-+{
-+  if (!fts_debug)
-+    return;
-+
-+  /* Make a writable copy.  */
-+  I_ring fd_w = sp->fts_fd_ring;
-+
-+  int cwd_fd = sp->fts_cwd_fd;
-+  cwd_fd = fcntl (cwd_fd, F_DUPFD_CLOEXEC, STDERR_FILENO + 1);
-+  struct devino dot = getdevino (cwd_fd);
-+  fprintf (stderr, "===== check ===== cwd: "PRINT_DEVINO"\n",
-+           dot.dev, dot.ino);
-+  while ( ! i_ring_empty (&fd_w))
-+    {
-+      int fd = i_ring_pop (&fd_w);
-+      if (0 <= fd)
-+        {
-+          int open_flags = O_SEARCH | O_CLOEXEC;
-+          int parent_fd = openat (cwd_fd, "..", open_flags);
-+          if (parent_fd < 0)
-+            {
-+              // Warn?
-+              break;
-+            }
-+          if (!same_fd (fd, parent_fd))
-+            {
-+              struct devino cwd = getdevino (fd);
-+              fprintf (stderr, "ring  : "PRINT_DEVINO"\n", cwd.dev, cwd.ino);
-+              struct devino c2 = getdevino (parent_fd);
-+              fprintf (stderr, "parent: "PRINT_DEVINO"\n", c2.dev, c2.ino);
-+              fts_assert (0);
-+            }
-+          close (cwd_fd);
-+          cwd_fd = parent_fd;
-+        }
-+    }
-+  close (cwd_fd);
-+}
-+#endif
-+
-+static unsigned short int
-+internal_function
-+fts_stat(FTSOBJ *sp, register FTSENTRY *p, bool follow)
-+{
-+        if (ISSET (FTS_LOGICAL)
-+            || (ISSET (FTS_COMFOLLOW) && p->fts_level == FTS_ROOTLEVEL))
-+                follow = true;
-+
-+        struct STRUCT_STAT *sbp = p->fts_statp;
-+
-+        /*
-+         * If doing a logical walk, or application requested FTS_FOLLOW, do
-+         * a stat(2).  If that fails, check for a nonexistent symlink.  If
-+         * fail, set the errno from the stat call.
-+         */
-+        int flags = follow ? 0 : AT_SYMLINK_NOFOLLOW;
-+        if (FSTATAT (sp->fts_cwd_fd, p->fts_accpath, sbp, flags) < 0)
-+          {
-+            if (follow && errno == ENOENT
-+                && 0 <= FSTATAT (sp->fts_cwd_fd, p->fts_accpath, sbp,
-+                                 AT_SYMLINK_NOFOLLOW))
-+              {
-+                __set_errno (0);
-+                return FTS_SLNONE;
-+              }
-+
-+            p->fts_errno = errno;
-+           memset (sbp, 0, sizeof *sbp);
-+            return FTS_NS;
-+          }
-+
-+        if (S_ISDIR(sbp->st_mode)) {
-+                if (ISDOT(p->fts_name)) {
-+                        /* Command-line "." and ".." are real directories. */
-+                        return (p->fts_level == FTS_ROOTLEVEL ? FTS_D : FTS_DOT);
-+                }
-+
-+                return (FTS_D);
-+        }
-+        if (S_ISLNK(sbp->st_mode))
-+                return (FTS_SL);
-+        if (S_ISREG(sbp->st_mode))
-+                return (FTS_F);
-+        return (FTS_DEFAULT);
-+}
-+
-+static int
-+fts_compar (void const *a, void const *b)
-+{
-+  /* Convert A and B to the correct types, to pacify the compiler, and
-+     for portability to bizarre hosts where "void const *" and "FTSENT
-+     const **" differ in runtime representation.  The comparison
-+     function cannot modify *a and *b, but there is no compile-time
-+     check for this.  */
-+  FTSENTRY const **pa = (FTSENTRY const **) a;
-+  FTSENTRY const **pb = (FTSENTRY const **) b;
-+  return FTSENT_FTS(pa[0])->fts_compar (pa, pb);
-+}
-+
-+static FTSENTRY *
-+internal_function
-+fts_sort (FTSOBJ *sp, FTSENTRY *head, register size_t nitems)
-+{
-+        register FTSENTRY **ap, *p;
-+
-+        /* On most modern hosts, void * and FTSENT ** have the same
-+           run-time representation, and one can convert sp->fts_compar to
-+           the type qsort expects without problem.  Use the heuristic that
-+           this is OK if the two pointer types are the same size, and if
-+           converting FTSENT ** to uintptr_t is the same as converting
-+           FTSENT ** to void * and then to uintptr_t.  This heuristic isn't
-+           valid in general but we don't know of any counterexamples.  */
-+        FTSENTRY *dummy;
-+        int (*compare) (void const *, void const *) =
-+          ((sizeof &dummy == sizeof (void *)
-+            && (uintptr_t) &dummy == (uintptr_t) (void *) &dummy)
-+           ? (int (*) (void const *, void const *)) sp->fts_compar
-+           : fts_compar);
-+
-+        /*
-+         * Construct an array of pointers to the structures and call qsort(3).
-+         * Reassemble the array in the order returned by qsort.  If unable to
-+         * sort for memory reasons, return the directory entries in their
-+         * current order.  Allocate enough space for the current needs plus
-+         * 40 so don't realloc one entry at a time.
-+         */
-+        if (nitems > sp->fts_nitems) {
-+                sp->fts_nitems = nitems + 40;
-+                FTSENTRY **a;
-+                if (! (a = reallocarray (sp->fts_array,
-+                                         sp->fts_nitems, sizeof *a))) {
-+                        free(sp->fts_array);
-+                        sp->fts_array = NULL;
-+                        sp->fts_nitems = 0;
-+                        return (head);
-+                }
-+                sp->fts_array = a;
-+        }
-+        for (ap = sp->fts_array, p = head; p; p = p->fts_link)
-+                *ap++ = p;
-+        qsort((void *)sp->fts_array, nitems, sizeof(FTSENTRY *), compare);
-+        for (head = *(ap = sp->fts_array); --nitems; ++ap)
-+                ap[0]->fts_link = ap[1];
-+        ap[0]->fts_link = NULL;
-+        return (head);
-+}
-+
-+static FTSENTRY *
-+internal_function
-+fts_alloc (FTSOBJ *sp, const char *name, register size_t namelen)
-+{
-+        /*
-+         * The file name is a variable length array.  Allocate the FTSENT
-+         * structure and the file name in one chunk.
-+         */
-+        size_t len = FLEXSIZEOF(FTSENT, fts_name, namelen + 1);
-+	register FTSENTRY *p;
-+#if !_LIBC
-+        p = malloc(len);
-+        if (p == NULL)
-+                return (NULL);
-+#else
-+	/*
-+	 * For glibc, we use a wrapper struct to provide the extra required
-+	 * fields without changing the FSENT layout.
-+	 */
-+	len += sizeof (struct FTSENT_wrapper);
-+	struct FTSENT_wrapper *wrapper = malloc(len);
-+	if (wrapper == NULL)
-+		return (NULL);
-+	p = &wrapper->ent;
-+        p->fts_statp = &wrapper->fts_stat;
-+#endif
-+
-+        /* Copy the name and guarantee NUL termination. */
-+        memcpy(p->fts_name, name, namelen);
-+        p->fts_name[namelen] = '\0';
-+
-+        p->fts_namelen = namelen;
-+        FTSENT_FTS(p)= sp;
-+        p->fts_path = sp->fts_path;
-+        p->fts_errno = 0;
-+        FTSENT_DIRP(p) = NULL;
-+        p->fts_flags = 0;
-+        p->fts_instr = FTS_NOINSTR;
-+        p->fts_number = 0;
-+        p->fts_pointer = NULL;
-+        return (p);
-+}
-+
-+static void
-+internal_function
-+fts_lfree (register FTSENTRY *head)
-+{
-+        int saved_errno = errno;
-+
-+        /* Free a linked list of structures. */
-+        register FTSENTRY *p;
-+        while ((p = head)) {
-+                head = head->fts_link;
-+                if (FTSENT_DIRP(p))
-+                        closedir (FTSENT_DIRP(p));
-+                free(FTSENT_WRAPPER(p));
-+        }
-+
-+        __set_errno (saved_errno);
-+}
-+
-+/*
-+ * Allow essentially unlimited file name lengths; find, rm, ls should
-+ * all work on any tree.  Most systems will allow creation of file
-+ * names much longer than MAXPATHLEN, even though the kernel won't
-+ * resolve them.  Add the size (not just what's needed) plus 256 bytes
-+ * so don't realloc the file name 2 bytes at a time.
-+ */
-+static bool
-+internal_function
-+fts_palloc (FTSOBJ *sp, size_t more)
-+{
-+        size_t new_len = sp->fts_pathlen + more + 256;
-+
-+        /*
-+         * See if fts_pathlen would overflow.
-+         */
-+        if (new_len < sp->fts_pathlen) {
-+                free(sp->fts_path);
-+                sp->fts_path = NULL;
-+                __set_errno (ENAMETOOLONG);
-+                return false;
-+        }
-+        sp->fts_pathlen = new_len;
-+        char *p = realloc(sp->fts_path, sp->fts_pathlen);
-+        if (p == NULL) {
-+                free(sp->fts_path);
-+                sp->fts_path = NULL;
-+                return false;
-+        }
-+        sp->fts_path = p;
-+        return true;
-+}
-+
-+/*
-+ * When the file name is realloc'd, have to fix all of the pointers in
-+ *  structures already returned.
-+ */
-+static void
-+internal_function
-+fts_padjust (FTSOBJ *sp, FTSENTRY *head)
-+{
-+        char *addr = sp->fts_path;
-+
-+        /* This code looks at bit-patterns of freed pointers to
-+           relocate them, so it relies on undefined behavior.  If this
-+           trick does not work on your platform, please report a bug.  */
-+
-+#define ADJUST(p) do {                                                  \
-+        uintptr_t old_accpath = (uintptr_t) (p)->fts_accpath;           \
-+        if (old_accpath != (uintptr_t) (p)->fts_name) {                 \
-+                (p)->fts_accpath =                                      \
-+                  addr + (old_accpath - (uintptr_t) (p)->fts_path);     \
-+        }                                                               \
-+        (p)->fts_path = addr;                                           \
-+} while (0)
-+        /* Adjust the current set of children. */
-+        for (FTSENTRY *p = sp->fts_child; p; p = p->fts_link)
-+                ADJUST(p);
-+
-+        /* Adjust the rest of the tree, including the current level. */
-+        for (FTSENTRY *p = head; p->fts_level >= FTS_ROOTLEVEL;) {
-+                ADJUST(p);
-+                p = p->fts_link ? p->fts_link : p->fts_parent;
-+        }
-+}
-+
-+static size_t
-+internal_function _GL_ATTRIBUTE_PURE
-+fts_maxarglen (char * const *argv)
-+{
-+        size_t max;
-+
-+        for (max = 0; *argv; ++argv) {
-+                size_t len = strlen(*argv);
-+                if (len > max)
-+                        max = len;
-+        }
-+        return (max + 1);
-+}
-+
-+/*
-+ * Change to dir specified by fd or file name without getting
-+ * tricked by someone changing the world out from underneath us.
-+ * Assumes p->fts_statp->st_dev and p->fts_statp->st_ino are filled in.
-+ * If FD is non-negative, expect it to be used after this function returns,
-+ * and to be closed eventually.  So don't pass e.g., 'dirfd(dirp)' and then
-+ * do closedir(dirp), because that would invalidate the saved FD.
-+ * Upon failure, close FD immediately and return nonzero.
-+ */
-+static int
-+internal_function
-+fts_safe_changedir (FTSOBJ *sp, FTSENTRY *p, int fd, char const *dir)
-+{
-+        fts_assert (0 <= fd || dir != NULL);
-+        bool is_dotdot = dir && streq (dir, "..");
-+
-+        /* This clause handles the unusual case in which FTS_NOCHDIR
-+           is specified, along with FTS_CWDFD.  In that case, there is
-+           no need to change even the virtual cwd file descriptor.
-+           However, if FD is non-negative, we do close it here.  */
-+        if (ISSET (FTS_NOCHDIR))
-+          {
-+            if (ISSET (FTS_CWDFD) && 0 <= fd)
-+              close (fd);
-+            return 0;
-+          }
-+
-+        if (fd < 0 && is_dotdot && ISSET (FTS_CWDFD))
-+          {
-+            /* When possible, skip the diropen and subsequent fstat+dev/ino
-+               comparison.  I.e., when changing to parent directory
-+               (chdir ("..")), use a file descriptor from the ring and
-+               save the overhead of diropen+fstat, as well as avoiding
-+               failure when we lack "x" access to the virtual cwd.  */
-+            if ( ! i_ring_empty (&sp->fts_fd_ring))
-+              {
-+                int parent_fd;
-+                fd_ring_print (sp, stderr, "pre-pop");
-+                parent_fd = i_ring_pop (&sp->fts_fd_ring);
-+                if (0 <= parent_fd)
-+                  {
-+                    fd = parent_fd;
-+                    dir = NULL;
-+                  }
-+              }
-+          }
-+
-+        int newfd = fd;
-+        if (fd < 0 && (newfd = diropen (sp, dir)) < 0)
-+          return -1;
-+
-+        /* The following dev/inode check is necessary if we're doing a
-+           "logical" traversal (through symlinks, a la chown -L), if the
-+           system lacks O_NOFOLLOW support, or if we're changing to ".."
-+           (but not via a popped file descriptor).  When changing to the
-+           name "..", O_NOFOLLOW can't help.  In general, when the target is
-+           not "..", diropen's use of O_NOFOLLOW ensures we don't mistakenly
-+           follow a symlink, so we can avoid the expense of this fstat.  */
-+        int ret;
-+        if (ISSET(FTS_LOGICAL) || ! HAVE_WORKING_O_NOFOLLOW
-+            || (dir && streq (dir, "..")))
-+          {
-+            struct STRUCT_STAT sb;
-+            if (FSTAT (newfd, &sb))
-+              {
-+                ret = -1;
-+                goto bail;
-+              }
-+            if (p->fts_statp->st_dev != sb.st_dev
-+                || p->fts_statp->st_ino != sb.st_ino)
-+              {
-+                __set_errno (ENOENT);           /* disinformation */
-+                ret = -1;
-+                goto bail;
-+              }
-+          }
-+
-+        if (ISSET(FTS_CWDFD))
-+          {
-+            cwd_advance_fd (sp, newfd, ! is_dotdot);
-+            return 0;
-+          }
-+
-+        ret = fchdir(newfd);
-+bail:
-+        if (fd < 0)
-+          {
-+            int oerrno = errno;
-+            (void)close(newfd);
-+            __set_errno (oerrno);
-+          }
-+        return ret;
-+}
-diff --git a/io/fts64-time64.c b/io/fts64-time64.c
-index 29f2dbc28cc7a11c..6a1053194eec51ba 100644
---- a/io/fts64-time64.c
-+++ b/io/fts64-time64.c
-@@ -33,5 +33,5 @@
- # define STRUCT_STATFS      statfs64
- # define FSTATFS            __fstatfs64
- 
--# include "fts-common.c"
-+# include "fts.c"
- #endif
-diff --git a/io/fts64.c b/io/fts64.c
-index 1efa06ab3bef0643..a6f607a87383f4a7 100644
---- a/io/fts64.c
-+++ b/io/fts64.c
-@@ -16,11 +16,11 @@
-    License along with the GNU C Library; if not, see
-    <https://www.gnu.org/licenses/>.  */
- 
--#define FTS_OPEN __fts64_open
--#define FTS_CLOSE __fts64_close
--#define FTS_READ __fts64_read
--#define FTS_SET __fts64_set
--#define FTS_CHILDREN __fts64_children
-+#define FTS_OPEN fts64_open
-+#define FTS_CLOSE fts64_close
-+#define FTS_READ fts64_read
-+#define FTS_SET fts64_set
-+#define FTS_CHILDREN fts64_children
- #define FTSOBJ FTS64
- #define FTSENTRY FTSENT64
- #define INO_T ino64_t
-@@ -30,30 +30,4 @@
- #define STRUCT_STATFS statfs64
- #define FSTATFS __fstatfs64
- 
--#define fts_open __rename_fts_open
--#define fts_close __rename_fts_close
--#define fts_read __rename_fts_read
--#define fts_set __rename_fts_set
--#define fts_children __rename_fts_children
--
--#include "fts-common.c"
--
--#undef fts_open
--#undef fts_close
--#undef fts_read
--#undef fts_set
--#undef fts_children
--
--weak_alias (__fts64_open, fts64_open)
--weak_alias (__fts64_close, fts64_close)
--weak_alias (__fts64_read, fts64_read)
--weak_alias (__fts64_set, fts64_set)
--weak_alias (__fts64_children, fts64_children)
--
--#ifdef __OFF_T_MATCHES_OFF64_T
--weak_alias (__fts64_open, fts_open)
--weak_alias (__fts64_close, fts_close)
--weak_alias (__fts64_read, fts_read)
--weak_alias (__fts64_set, fts_set)
--weak_alias (__fts64_children, fts_children)
--#endif
-+#include "fts.c"
-diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/fts.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/fts.c
-new file mode 100644
-index 0000000000000000..d0c62e6195eadc63
---- /dev/null
-+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/fts.c
-@@ -0,0 +1 @@
-+#include <io/fts.c>
-diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/fts64.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/fts64.c
-new file mode 100644
-index 0000000000000000..2472f8bf75968b36
---- /dev/null
-+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/fts64.c
-@@ -0,0 +1 @@
-+#include <io/fts64.c>
-diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/fts.c b/sysdeps/unix/sysv/linux/x86_64/x32/fts.c
-new file mode 100644
-index 0000000000000000..980573ed68928441
---- /dev/null
-+++ b/sysdeps/unix/sysv/linux/x86_64/x32/fts.c
-@@ -0,0 +1 @@
-+#include <sysdeps/wordsize-64/fts.c>
-diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/fts64.c b/sysdeps/unix/sysv/linux/x86_64/x32/fts64.c
-new file mode 100644
-index 0000000000000000..221d1b5608e8692f
---- /dev/null
-+++ b/sysdeps/unix/sysv/linux/x86_64/x32/fts64.c
-@@ -0,0 +1 @@
-+#include <sysdeps/wordsize-64/fts64.c>
-diff --git a/sysdeps/wordsize-64/fts.c b/sysdeps/wordsize-64/fts.c
-new file mode 100644
-index 0000000000000000..159dc1febe4980f7
---- /dev/null
-+++ b/sysdeps/wordsize-64/fts.c
-@@ -0,0 +1,19 @@
-+#define fts64_open __rename_fts64_open
-+#define fts64_close __rename_fts64_close
-+#define fts64_read __rename_fts64_read
-+#define fts64_set __rename_fts64_set
-+#define fts64_children __rename_fts64_children
-+
-+#include "../../io/fts.c"
-+
-+#undef fts64_open
-+#undef fts64_close
-+#undef fts64_read
-+#undef fts64_set
-+#undef fts64_children
-+
-+weak_alias (fts_open, fts64_open)
-+weak_alias (fts_close, fts64_close)
-+weak_alias (fts_read, fts64_read)
-+weak_alias (fts_set, fts64_set)
-+weak_alias (fts_children, fts64_children)
-diff --git a/sysdeps/wordsize-64/fts64.c b/sysdeps/wordsize-64/fts64.c
-new file mode 100644
-index 0000000000000000..f2848fc3e4c08625
---- /dev/null
-+++ b/sysdeps/wordsize-64/fts64.c
-@@ -0,0 +1 @@
-+/* Defined in fts.c.  */
--- 
-2.53.0
-

diff --git a/glibc-rh2457183-2.patch b/glibc-rh2457183-2.patch
deleted file mode 100644
index 53374bd..0000000
--- a/glibc-rh2457183-2.patch
+++ /dev/null
@@ -1,6222 +0,0 @@
-Revert "io: Use gnulib fts implementation (BZ 22944, BZ 20331)"
-
-This reverts commit 99303f387179332d64e5ee34a6b58e82a523bae5.
-
-Reason for revert: This change breaks dracut due to the way it uses
-fts: <https://bugzilla.redhat.com/show_bug.cgi?id=2457183>
-
-diff --git a/SHARED-FILES b/SHARED-FILES
-index 126aaf096d93371c..b9d9cdc9d04cab38 100644
---- a/SHARED-FILES
-+++ b/SHARED-FILES
-@@ -36,22 +36,8 @@ gnulib:
-   # Merged from gnulib 2025-10-29 (gnulib commit 1790ef25d8)
-   include/intprops.h
-   include/intprops-internal.h
--  # Merged from gnulib 2026-02-16
--  include/assure.h
--  include/flexmember.h
--  include/hash.h
--  include/next-prime.h
--  include/xalloc-oversized.h
-   # Merged from gnulib 2021-09-21
-   include/regex.h
--  # Merged from gnulib 2026-02-16
--  io/cycle-check.c
--  io/cycle-check.h
--  io/dev-ino.h
--  io/fts-cycle.c
--  io/fts.c
--  io/i-ring.c
--  io/same-inode.h
-   locale/programs/3level.h
-   # Merged from gnulib 2014-6-23
-   malloc/obstack.c
-@@ -61,9 +47,7 @@ gnulib:
-   misc/error.c
-   misc/error.h
-   misc/getpass.c
--  misc/hash.c
-   misc/mkdtemp.c
--  misc/next-prime.c
-   # Merged from gnulib 2021-09-21
-   misc/sys/cdefs.h
-   posix/fnmatch_loop.c
-diff --git a/dirent/scandirat.c b/dirent/scandirat.c
-index d40c0828f19a9b2b..31ec9662b0b42173 100644
---- a/dirent/scandirat.c
-+++ b/dirent/scandirat.c
-@@ -23,8 +23,7 @@ __scandirat (int dfd, const char *dir, struct dirent ***namelist,
- 	     int (*select) (const struct dirent *),
- 	     int (*cmp) (const struct dirent **, const struct dirent **))
- {
--  return __scandir_tail (__opendirat (dfd, dir, 0, NULL), namelist, select,
--			 cmp);
-+  return __scandir_tail (__opendirat (dfd, dir), namelist, select, cmp);
- }
- weak_alias (__scandirat, scandirat)
- #endif
-diff --git a/dirent/scandirat64.c b/dirent/scandirat64.c
-index cb1821174e693dce..fb010fac28f236c1 100644
---- a/dirent/scandirat64.c
-+++ b/dirent/scandirat64.c
-@@ -24,8 +24,7 @@ scandirat64 (int dfd, const char *dir, struct dirent64 ***namelist,
- 	     int (*select) (const struct dirent64 *),
- 	     int (*cmp) (const struct dirent64 **, const struct dirent64 **))
- {
--  return __scandir64_tail (__opendirat (dfd, dir, 0, NULL), namelist, select,
--			   cmp);
-+  return __scandir64_tail (__opendirat (dfd, dir), namelist, select, cmp);
- }
- 
- #if _DIRENT_MATCHES_DIRENT64
-diff --git a/include/assure.h b/include/assure.h
-deleted file mode 100644
-index edc72591d1283b4a..0000000000000000
---- a/include/assure.h
-+++ /dev/null
-@@ -1,57 +0,0 @@
--/* Run-time assert-like macros.
--
--   Copyright (C) 2014-2026 Free Software Foundation, Inc.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--/* Written by Paul Eggert.  */
--
--#ifndef _GL_ASSURE_H
--#define _GL_ASSURE_H
--
--#include <assert.h>
--#include "verify.h"
--
--/* Evaluate an assertion E that is guaranteed to be true.
--   If NDEBUG is not defined, abort the program if E is false.
--   If NDEBUG is defined, the compiler can assume E and behavior is
--   undefined if E is false, fails to evaluate, or has side effects.
--
--   Unlike standard 'assert', this macro evaluates E even when NDEBUG
--   is defined, so as to catch typos, avoid some GCC warnings, and
--   improve performance when E is simple enough.
--
--   Also see the documentation for 'assume' in verify.h.  */
--
--#ifdef NDEBUG
--# define affirm(E) assume (E)
--#else
--# define affirm(E) assert (E)
--#endif
--
--/* Check E's value at runtime, and report an error and abort if not.
--   However, do nothing if NDEBUG is defined.
--
--   Unlike standard 'assert', this macro compiles E even when NDEBUG
--   is defined, so as to catch typos and avoid some GCC warnings.
--   Unlike 'affirm', it is OK for E to use hard-to-optimize features,
--   since E is not executed if NDEBUG is defined.  */
--
--#ifdef NDEBUG
--# define assure(E) ((void) (0 && (E)))
--#else
--# define assure(E) assert (E)
--#endif
--
--#endif
-diff --git a/include/dirent.h b/include/dirent.h
-index 9a4bd5a1e3796838..d7567f5e866e6ad3 100644
---- a/include/dirent.h
-+++ b/include/dirent.h
-@@ -16,8 +16,7 @@ struct scandir_cancel_struct
- 
- /* 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 *__opendirat (int dfd, const char *__name) attribute_hidden;
- extern DIR *__fdopendir (int __fd) attribute_hidden;
- extern int __closedir (DIR *__dirp) attribute_hidden;
- extern struct dirent *__readdir (DIR *__dirp) attribute_hidden;
-diff --git a/include/flexmember.h b/include/flexmember.h
-deleted file mode 100644
-index c6bb2842ec7febb1..0000000000000000
---- a/include/flexmember.h
-+++ /dev/null
-@@ -1,77 +0,0 @@
--/* Sizes of structs with flexible array members.
--
--   Copyright 2016-2026 Free Software Foundation, Inc.
--
--   This file is part of the GNU C Library.
--
--   The GNU C Library is free software; you can redistribute it and/or
--   modify it under the terms of the GNU Lesser General Public
--   License as published by the Free Software Foundation; either
--   version 2.1 of the License, or (at your option) any later version.
--
--   The GNU C Library 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
--   Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public
--   License along with the GNU C Library; if not, see
--   <https://www.gnu.org/licenses/>.
--
--   Written by Paul Eggert.  */
--
--/* This file uses _Alignof.  */
--#if !_LIBC && !_GL_CONFIG_H_INCLUDED
-- #error "Please include config.h first."
--#endif
--
--#include <stddef.h>
--
--/* Nonzero multiple of alignment of TYPE, suitable for FLEXSIZEOF below.
--   If _Alignof might not exist or might not work correctly on
--   structs with flexible array members, use a pessimistic bound that is
--   safe in practice even if FLEXIBLE_ARRAY_MEMBER is 1.
--   Otherwise, use _Alignof to get a tighter bound.  */
--
--#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 || defined _Alignof
--# define FLEXALIGNOF(type) (sizeof (type) & ~ (sizeof (type) - 1))
--#else
--# define FLEXALIGNOF(type) _Alignof (type)
--#endif
--
--/* Yield a properly aligned upper bound on the size of a struct of
--   type TYPE with a flexible array member named MEMBER that is
--   followed by N bytes of other data.  The result is suitable as an
--   argument to malloc.  For example:
--
--     struct s { int a; char d[FLEXIBLE_ARRAY_MEMBER]; };
--     struct s *p = malloc (FLEXSIZEOF (struct s, d, n * sizeof (char)));
--
--   FLEXSIZEOF (TYPE, MEMBER, N) is not simply (sizeof (TYPE) + N),
--   since FLEXIBLE_ARRAY_MEMBER may be 1 on pre-C11 platforms.  Nor is
--   it simply (offsetof (TYPE, MEMBER) + N), as that might yield a size
--   that causes malloc to yield a pointer that is not properly aligned
--   for TYPE; for example, if sizeof (int) == alignof (int) == 4,
--   malloc (offsetof (struct s, d) + 3 * sizeof (char)) is equivalent
--   to malloc (7) and might yield a pointer that is not a multiple of 4
--   (which means the pointer is not properly aligned for struct s),
--   whereas malloc (FLEXSIZEOF (struct s, d, 3 * sizeof (char))) is
--   equivalent to malloc (8) and must yield a pointer that is a
--   multiple of 4.
--
--   Yield a value less than N if and only if arithmetic overflow occurs.  */
--
--#define FLEXSIZEOF(type, member, n) \
--   ((offsetof (type, member) + FLEXALIGNOF (type) - 1 + (n)) \
--    & ~ (FLEXALIGNOF (type) - 1))
--
--/* Yield a properly aligned upper bound on the size of a struct of
--   type TYPE with a flexible array member named MEMBER that has N
--   elements.  The result is suitable as an argument to malloc.
--   For example:
--
--     struct s { int a; double d[FLEXIBLE_ARRAY_MEMBER]; };
--     struct s *p = malloc (FLEXNSIZEOF (struct s, d, n));
-- */
--#define FLEXNSIZEOF(type, member, n) \
--  FLEXSIZEOF (type, member, (n) * sizeof (((type *) 0)->member[0]))
-diff --git a/include/fts.h b/include/fts.h
-index 972884647bd5c2c1..ea36a9b9be29f88a 100644
---- a/include/fts.h
-+++ b/include/fts.h
-@@ -17,13 +17,6 @@ typedef struct
-   int fts_nitems;
-   int (*fts_compar) (const void *, const void *);
-   int fts_options;
--  int fts_cwd_fd;
--  struct hash_table *fts_leaf_optimization_works_ht;
--  union {
--	  struct hash_table *ht;
--	  struct cycle_check_state *state;
--  } fts_cycle;
--  __I_ring fts_fd_ring;
- } FTS64_TIME64;
- 
- typedef struct _ftsent64_time64
-diff --git a/include/hash.h b/include/hash.h
-deleted file mode 100644
-index d3c80aeedf32a75f..0000000000000000
---- a/include/hash.h
-+++ /dev/null
-@@ -1,331 +0,0 @@
--/* hash - hashing table processing.
--   Copyright (C) 1998-1999, 2001, 2003, 2009-2026 Free Software Foundation,
--   Inc.
--   Written by Jim Meyering <meyering@ascend.com>, 1998.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--/* A generic hash table package.  */
--
--/* Make sure USE_OBSTACK is defined to 1 if you want the allocator to use
--   obstacks instead of malloc, and recompile 'hash.c' with same setting.  */
--
--#ifndef HASH_H_
--# define HASH_H_
--
--/* This file uses _GL_ATTRIBUTE_DEALLOC, _GL_ATTRIBUTE_DEPRECATED,
--   _GL_ATTRIBUTE_MALLOC, _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_PURE,
--   _GL_ATTRIBUTE_RETURNS_NONNULL.  */
--#if !_LIBC && !_GL_CONFIG_H_INCLUDED
-- #error "Please include config.h first."
--#endif
--
--# include <stdbool.h>
--# include <stdio.h>
--
--# ifdef _LIBC
--#  define _GL_ATTRIBUTE_NODISCARD          __attribute_warn_unused_result__
--#  define _GL_ATTRIBUTE_MALLOC             __attribute_malloc__
--#  define _GL_ATTRIBUTE_DEALLOC(__a, __b)  __attr_dealloc (__a, __b)
--#  define _GL_ATTRIBUTE_RETURNS_NONNULL    __returns_nonnull
--#  define GNULIB_HASHCODE_STRING1          0
--#  define hash_get_n_buckets               __hash_get_n_buckets
--#  define hash_get_n_buckets_used          __hash_get_n_buckets_used
--#  define hash_get_n_entries               __hash_get_n_entries
--#  define hash_get_max_bucket_length       __hash_get_max_bucket_length
--#  define hash_table_ok                    __hash_table_ok
--#  define hash_print_statistics            __hash_print_statistics
--#  define hash_lookup                      __hash_lookup
--#  define hash_get_first                   __hash_get_first
--#  define hash_get_next                    __hash_get_next
--#  define hash_get_entries                 __hash_get_entries
--#  define hash_do_for_each                 __hash_do_for_each
--#  define hash_reset_tuning                __hash_reset_tuning
--#  define hash_free                        __hash_free
--#  define hash_initialize                  __hash_initialize
--#  define hash_xinitialize                 __hash_xinitialize
--#  define hash_clear                       __hash_clear
--#  define hash_rehash                      __hash_rehash
--#  define hash_insert                      __hash_insert
--#  define hash_xinsert                     __hash_xinsert
--#  define hash_insert_if_absent            __hash_insert_if_absent
--#  define hash_remove                      __hash_remove
--# else
--#  define attribute_hidden
--# endif
--
--# ifdef __cplusplus
--extern "C" {
--# endif
--
--struct hash_tuning
--  {
--    /* This structure is mainly used for 'hash_initialize', see the block
--       documentation of 'hash_reset_tuning' for more complete comments.  */
--
--    float shrink_threshold;     /* ratio of used buckets to trigger a shrink */
--    float shrink_factor;        /* ratio of new smaller size to original size */
--    float growth_threshold;     /* ratio of used buckets to trigger a growth */
--    float growth_factor;        /* ratio of new bigger size to original size */
--    bool is_n_buckets;          /* if CANDIDATE really means table size */
--  };
--
--typedef struct hash_tuning Hash_tuning;
--
--struct hash_table;
--
--typedef struct hash_table Hash_table;
--
--/*
-- * Information and lookup.
-- */
--
--/* The following few functions provide information about the overall hash
--   table organization: the number of entries, number of buckets and maximum
--   length of buckets.  */
--
--/* Return the number of buckets in the hash table.  The table size, the total
--   number of buckets (used plus unused), or the maximum number of slots, are
--   the same quantity.  */
--extern size_t hash_get_n_buckets (const Hash_table *table)
--       _GL_ATTRIBUTE_PURE attribute_hidden;
--
--/* Return the number of slots in use (non-empty buckets).  */
--extern size_t hash_get_n_buckets_used (const Hash_table *table)
--       _GL_ATTRIBUTE_PURE attribute_hidden;
--
--/* Return the number of active entries.  */
--extern size_t hash_get_n_entries (const Hash_table *table)
--       _GL_ATTRIBUTE_PURE attribute_hidden;
--
--/* Return the length of the longest chain (bucket).  */
--extern size_t hash_get_max_bucket_length (const Hash_table *table)
--       _GL_ATTRIBUTE_PURE attribute_hidden;
--
--/* Do a mild validation of a hash table, by traversing it and checking two
--   statistics.  */
--extern bool hash_table_ok (const Hash_table *table)
--       _GL_ATTRIBUTE_PURE attribute_hidden;
--
--extern void hash_print_statistics (const Hash_table *table, FILE *stream)
--       attribute_hidden;
--
--/* If ENTRY matches an entry already in the hash table, return the
--   entry from the table.  Otherwise, return NULL.  */
--extern void *hash_lookup (const Hash_table *table, const void *entry)
--       attribute_hidden;
--
--/*
-- * Walking.
-- */
--
--/* The functions in this page traverse the hash table and process the
--   contained entries.  For the traversal to work properly, the hash table
--   should not be resized nor modified while any particular entry is being
--   processed.  In particular, entries should not be added, and an entry
--   may be removed only if there is no shrink threshold and the entry being
--   removed has already been passed to hash_get_next.  */
--
--/* Return the first data in the table, or NULL if the table is empty.  */
--extern void *hash_get_first (const Hash_table *table)
--       _GL_ATTRIBUTE_PURE attribute_hidden;
--
--/* Return the user data for the entry following ENTRY, where ENTRY has been
--   returned by a previous call to either 'hash_get_first' or 'hash_get_next'.
--   Return NULL if there are no more entries.  */
--extern void *hash_get_next (const Hash_table *table, const void *entry)
--       attribute_hidden;
--
--/* Fill BUFFER with pointers to active user entries in the hash table, then
--   return the number of pointers copied.  Do not copy more than BUFFER_SIZE
--   pointers.  */
--extern size_t hash_get_entries (const Hash_table *table, void **buffer,
--                                size_t buffer_size)
--       attribute_hidden;
--
--typedef bool (*Hash_processor) (void *entry, void *processor_data);
--
--/* Call a PROCESSOR function for each entry of a hash table, and return the
--   number of entries for which the processor function returned success.  A
--   pointer to some PROCESSOR_DATA which will be made available to each call to
--   the processor function.  The PROCESSOR accepts two arguments: the first is
--   the user entry being walked into, the second is the value of PROCESSOR_DATA
--   as received.  The walking continue for as long as the PROCESSOR function
--   returns nonzero.  When it returns zero, the walking is interrupted.  */
--extern size_t hash_do_for_each (const Hash_table *table,
--                                Hash_processor processor, void *processor_data)
--       attribute_hidden;
--
--/* Return a hash code of ENTRY, in the range 0..TABLE_SIZE-1.
--   This hash code function must have the property that if the comparator of
--   ENTRY1 and ENTRY2 returns true, the hasher returns the same value for ENTRY1
--   and for ENTRY2.
--   The hash code function typically computes an unsigned integer and at the end
--   performs a % TABLE_SIZE modulo operation.  This modulo operation is performed
--   as part of this hash code function, not by the caller, because in some cases
--   the unsigned integer will be a 'size_t', in other cases an 'uintmax_t' or
--   even larger.  */
--typedef size_t (*Hash_hasher) (const void *entry, size_t table_size);
--
--/* Compare two entries, ENTRY1 (being looked up or being inserted) and
--   ENTRY2 (already in the table) for equality.  Return true for equal,
--   false otherwise.  */
--typedef bool (*Hash_comparator) (const void *entry1, const void *entry2);
--
--/* This function is invoked when an ENTRY is removed from the hash table.  */
--typedef void (*Hash_data_freer) (void *entry);
--
--/*
-- * Allocation and clean-up.
-- */
--
--extern void hash_reset_tuning (Hash_tuning *tuning)
--       attribute_hidden;
--
--/* Reclaim all storage associated with a hash table.  If a data_freer
--   function has been supplied by the user when the hash table was created,
--   this function applies it to the data of each entry before freeing that
--   entry.  This function preserves errno, like 'free'.  */
--extern void hash_free (Hash_table *table)
--       attribute_hidden;
--
--/* Allocate and return a new hash table, or NULL upon failure.  The initial
--   number of buckets is automatically selected so as to _guarantee_ that you
--   may insert at least CANDIDATE different user entries before any growth of
--   the hash table size occurs.  So, if have a reasonably tight a-priori upper
--   bound on the number of entries you intend to insert in the hash table, you
--   may save some table memory and insertion time, by specifying it here.  If
--   the IS_N_BUCKETS field of the TUNING structure is true, the CANDIDATE
--   argument has its meaning changed to the wanted number of buckets.
--
--   TUNING points to a structure of user-supplied values, in case some fine
--   tuning is wanted over the default behavior of the hasher.  If TUNING is
--   NULL, the default tuning parameters are used instead.  If TUNING is
--   provided but the values requested are out of bounds or might cause
--   rounding errors, return NULL.
--
--   The user-supplied HASHER function, when not NULL, accepts two
--   arguments ENTRY and TABLE_SIZE.  It computes, by hashing ENTRY contents, a
--   slot number for that entry which should be in the range 0..TABLE_SIZE-1.
--   This slot number is then returned.
--
--   The user-supplied COMPARATOR function, when not NULL, accepts two
--   arguments pointing to user data, it then returns true for a pair of entries
--   that compare equal, or false otherwise.  This function is internally called
--   on entries which are already known to hash to the same bucket index,
--   but which are distinct pointers.
--
--   The user-supplied DATA_FREER function, when not NULL, may be later called
--   with the user data as an argument, just before the entry containing the
--   data gets freed.  This happens from within 'hash_free' or 'hash_clear'.
--   You should specify this function only if you want these functions to free
--   all of your 'data' data.  This is typically the case when your data is
--   simply an auxiliary struct that you have malloc'd to aggregate several
--   values.
--
--   Set errno on failure; otherwise errno is unspecified.  */
--_GL_ATTRIBUTE_NODISCARD
--extern Hash_table *hash_initialize (size_t candidate,
--                                    const Hash_tuning *tuning,
--                                    Hash_hasher hasher,
--                                    Hash_comparator comparator,
--                                    Hash_data_freer data_freer)
--  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC (hash_free, 1)
--  attribute_hidden;
--
--/* Like hash_initialize, but invokes xalloc_die instead of returning NULL.  */
--/* This function is defined by module 'xhash'.  */
--_GL_ATTRIBUTE_NODISCARD
--extern Hash_table *hash_xinitialize (size_t candidate,
--                                     const Hash_tuning *tuning,
--                                     Hash_hasher hasher,
--                                     Hash_comparator comparator,
--                                     Hash_data_freer data_freer)
--  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC (hash_free, 1)
--  _GL_ATTRIBUTE_RETURNS_NONNULL
--  attribute_hidden;
--
--/* Make all buckets empty, placing any chained entries on the free list.
--   Apply the user-specified function data_freer (if any) to the data of any
--   affected entries.  */
--extern void hash_clear (Hash_table *table)
--  attribute_hidden;;
--
--/*
-- * Insertion and deletion.
-- */
--
--/* For an already existing hash table, change the number of buckets through
--   specifying CANDIDATE.  The contents of the hash table are preserved.  The
--   new number of buckets is automatically selected so as to _guarantee_ that
--   the table may receive at least CANDIDATE different user entries, including
--   those already in the table, before any other growth of the hash table size
--   occurs.  If TUNING->IS_N_BUCKETS is true, then CANDIDATE specifies the
--   exact number of buckets desired.  Return true iff the rehash succeeded,
--   false (setting errno) otherwise.  */
--_GL_ATTRIBUTE_NODISCARD
--extern bool hash_rehash (Hash_table *table, size_t candidate)
--       attribute_hidden;
--
--/* If ENTRY matches an entry already in the hash table, return the pointer
--   to the entry from the table.  Otherwise, insert ENTRY and return ENTRY.
--   Return NULL (setting errno) if the storage required for insertion
--   cannot be allocated.  This implementation does not support
--   duplicate entries or insertion of NULL.  */
--_GL_ATTRIBUTE_NODISCARD
--extern void *hash_insert (Hash_table *table, const void *entry)
--       attribute_hidden;
--
--/* Same as hash_insert, but invokes xalloc_die instead of returning NULL.  */
--/* This function is defined by module 'xhash'.  */
--extern void *hash_xinsert (Hash_table *table, const void *entry)
--       attribute_hidden;
--
--/* Insert ENTRY into hash TABLE if there is not already a matching entry.
--
--   Return -1 (setting errno) upon memory allocation failure.
--   Return 1 if insertion succeeded.
--   Return 0 if there is already a matching entry in the table,
--   and in that case, if MATCHED_ENT is non-NULL, set *MATCHED_ENT
--   to that entry.
--
--   This interface is easier to use than hash_insert when you must
--   distinguish between the latter two cases.  More importantly,
--   hash_insert is unusable for some types of ENTRY values.  When using
--   hash_insert, the only way to distinguish those cases is to compare
--   the return value and ENTRY.  That works only when you can have two
--   different ENTRY values that point to data that compares "equal".  Thus,
--   when the ENTRY value is a simple scalar, you must use
--   hash_insert_if_absent.  ENTRY must not be NULL.  */
--extern int hash_insert_if_absent (Hash_table *table, const void *entry,
--                                  const void **matched_ent)
--       attribute_hidden;
--
--/* If ENTRY is already in the table, remove it and return the just-deleted
--   data (the user may want to deallocate its storage).  If ENTRY is not in the
--   table, don't modify the table and return NULL.  */
--extern void *hash_remove (Hash_table *table, const void *entry)
--       attribute_hidden;
--
--
--# if GNULIB_HASHCODE_STRING1
--/* Include declarations of module 'hashcode-string1'.  */
--#  include "hashcode-string1.h"
--# endif
--
--# ifdef __cplusplus
--}
--# endif
--
--#endif
-diff --git a/include/next-prime.h b/include/next-prime.h
-deleted file mode 100644
-index 2ee965982b071133..0000000000000000
---- a/include/next-prime.h
-+++ /dev/null
-@@ -1,47 +0,0 @@
--/* Finding the next prime >= a given small integer.
--   Copyright (C) 1995-2026 Free Software Foundation, Inc.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--#ifndef _GL_NEXT_PRIME_H
--#define _GL_NEXT_PRIME_H
--
--/* This file uses _GL_ATTRIBUTE_CONST.  */
--#if !_LIBC && !_GL_CONFIG_H_INCLUDED
-- #error "Please include config.h first."
--#endif
--
--#include <stddef.h>
--
--#ifdef __cplusplus
--extern "C" {
--#endif
--
--#ifdef _LIBC
--# define next_prime __next_prime
--#else
--# define attribute_hidden
--#endif
--
--/* Round a given CANDIDATE number up to the nearest prime, and return that
--   prime.  Primes lower than 10 are merely skipped.  */
--extern size_t _GL_ATTRIBUTE_CONST next_prime (size_t candidate)
--  attribute_hidden;;
--
--
--#ifdef __cplusplus
--}
--#endif
--
--#endif /* _GL_NEXT_PRIME_H */
-diff --git a/include/xalloc-oversized.h b/include/xalloc-oversized.h
-deleted file mode 100644
-index cecdaec51ef4e30b..0000000000000000
---- a/include/xalloc-oversized.h
-+++ /dev/null
-@@ -1,65 +0,0 @@
--/* xalloc-oversized.h -- memory allocation size checking
--
--   Copyright (C) 1990-2000, 2003-2004, 2006-2026 Free Software Foundation, Inc.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--#ifndef XALLOC_OVERSIZED_H_
--#define XALLOC_OVERSIZED_H_
--
--#include <stddef.h>
--#include <stdint.h>
--
--/* True if N * S does not fit into both ptrdiff_t and size_t.
--   N and S should be nonnegative and free of side effects.
--   This expands to a constant expression if N and S are both constants.
--   By gnulib convention, SIZE_MAX represents overflow in size_t
--   calculations, so the conservative size_t-based dividend to use here
--   is SIZE_MAX - 1.  */
--#define __xalloc_oversized(n, s) \
--  ((s) != 0 \
--   && (PTRDIFF_MAX < SIZE_MAX ? PTRDIFF_MAX : SIZE_MAX - 1) / (s) < (n))
--
--/* Return 1 if and only if an array of N objects, each of size S,
--   cannot exist reliably because its total size in bytes would exceed
--   MIN (PTRDIFF_MAX, SIZE_MAX - 1).
--
--   N and S should be nonnegative and free of side effects.
--
--   Warning: (xalloc_oversized (N, S) ? NULL : malloc (N * S)) can
--   misbehave if N and S are both narrower than ptrdiff_t and size_t,
--   and can be rewritten as (xalloc_oversized (N, S) ?  NULL
--   : malloc (N * (size_t) S)).
--
--   This is a macro, not a function, so that it works even if an
--   argument exceeds MAX (PTRDIFF_MAX, SIZE_MAX).  */
--#if 7 <= __GNUC__ && !defined __clang__ && PTRDIFF_MAX < SIZE_MAX
--# define xalloc_oversized(n, s) \
--   __builtin_mul_overflow_p (n, s, (ptrdiff_t) 1)
--#elif 5 <= __GNUC__ && !defined __clang__ && !defined __ICC \
--      && PTRDIFF_MAX < SIZE_MAX
--# define xalloc_oversized(n, s) \
--   (__builtin_constant_p (n) && __builtin_constant_p (s) \
--    ? __xalloc_oversized (n, s) \
--    : __extension__ \
--        ({ ptrdiff_t __xalloc_count; \
--           __builtin_mul_overflow (n, s, &__xalloc_count); }))
--
--/* Other compilers use integer division; this may be slower but is
--   more portable.  */
--#else
--# define xalloc_oversized(n, s) __xalloc_oversized (n, s)
--#endif
--
--#endif /* !XALLOC_OVERSIZED_H_ */
-diff --git a/io/Makefile b/io/Makefile
-index 2a5b4dcb654f3352..80e50578b29f4d80 100644
---- a/io/Makefile
-+++ b/io/Makefile
-@@ -197,9 +197,7 @@ tests := \
-   tst-fcntl-lock-lfs \
-   tst-fstatat \
-   tst-fts \
--  tst-fts-bz22944 \
-   tst-fts-lfs \
--  tst-fts-newflags \
-   tst-ftw-bz26353 \
-   tst-ftw-bz28126 \
-   tst-ftw-lnk \
-diff --git a/io/cycle-check.c b/io/cycle-check.c
-deleted file mode 100644
-index 3a20d28aec897595..0000000000000000
---- a/io/cycle-check.c
-+++ /dev/null
-@@ -1,85 +0,0 @@
--
--/* help detect directory cycles efficiently
--
--   Copyright (C) 2003-2006, 2009-2026 Free Software Foundation, Inc.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--/* Written by Jim Meyering */
--
--#include <config.h>
--
--#include "cycle-check.h"
--
--#include <sys/types.h>
--#include <sys/stat.h>
--#include <stdio.h>
--#include <stdlib.h>
--
--#include "assure.h"
--
--#define CC_MAGIC 9827862
--
--/* Return true if I is a power of 2, or is zero.  */
--
--static bool
--is_zero_or_power_of_two (uintmax_t i)
--{
--  return (i & (i - 1)) == 0;
--}
--
--INTERNAL_DEF void
--cycle_check_init (struct cycle_check_state *state)
--{
--  state->chdir_counter = 0;
--  state->magic = CC_MAGIC;
--}
--
--/* In traversing a directory hierarchy, call this function once for each
--   descending chdir call, with SB corresponding to the chdir operand.
--   If SB corresponds to a directory that has already been seen,
--   return true to indicate that there is a directory cycle.
--   Note that this is done "lazily", which means that some of
--   the directories in the cycle may be processed twice before
--   the cycle is detected.  */
--
--INTERNAL_DEF bool
--cycle_check (struct cycle_check_state *state, struct STRUCT_STAT const *sb)
--{
--  assure (state->magic == CC_MAGIC);
--
--  /* If the current directory ever happens to be the same
--     as the one we last recorded for the cycle detection,
--     then it's obviously part of a cycle.  */
--  if (state->chdir_counter && SAME_INODE (*sb, state->dev_ino))
--    return true;
--
--  /* If the number of "descending" chdir calls is a power of two,
--     record the dev/ino of the current directory.  */
--  if (is_zero_or_power_of_two (++(state->chdir_counter)))
--    {
--      /* On all architectures that we know about, if the counter
--         overflows then there is a directory cycle here somewhere,
--         even if we haven't detected it yet.  Typically this happens
--         only after the counter is incremented 2**64 times, so it's a
--         fairly theoretical point.  */
--      if (state->chdir_counter == 0)
--        return true;
--
--      state->dev_ino.st_dev = sb->st_dev;
--      state->dev_ino.st_ino = sb->st_ino;
--    }
--
--  return false;
--}
-diff --git a/io/cycle-check.h b/io/cycle-check.h
-deleted file mode 100644
-index 0152992ced518125..0000000000000000
---- a/io/cycle-check.h
-+++ /dev/null
-@@ -1,70 +0,0 @@
--
--/* help detect directory cycles efficiently
--
--   Copyright (C) 2003-2004, 2006, 2009-2026 Free Software Foundation, Inc.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--/* Written by Jim Meyering */
--
--#ifndef CYCLE_CHECK_H
--#define CYCLE_CHECK_H 1
--
--#include <stdint.h>
--#include "dev-ino.h"
--#include "same-inode.h"
--
--#ifdef __cplusplus
--extern "C" {
--#endif
--
--#if _LIBC
--# define cycle_check_init __cycle_check_init
--# define cycle_check      __cycle_check
--# define INTERNAL_DEF     static
--#else
--# define INTERNAL_DEF
--#endif
--
--struct cycle_check_state
--{
--  struct dev_ino dev_ino;
--  uintmax_t chdir_counter;
--  int magic;
--};
--
--INTERNAL_DEF void cycle_check_init (struct cycle_check_state *state);
--INTERNAL_DEF bool cycle_check (struct cycle_check_state *state,
--			       struct STRUCT_STAT const *sb);
--
--#define CYCLE_CHECK_REFLECT_CHDIR_UP(State, SB_dir, SB_subdir) \
--  do                                                            \
--    {                                                           \
--      /* You must call cycle_check at least once before using this macro.  */ \
--      if ((State)->chdir_counter == 0)                          \
--        abort ();                                               \
--      if (SAME_INODE ((State)->dev_ino, SB_subdir))             \
--        {                                                       \
--          (State)->dev_ino.st_dev = (SB_dir).st_dev;            \
--          (State)->dev_ino.st_ino = (SB_dir).st_ino;            \
--        }                                                       \
--    }                                                           \
--  while (0)
--
--
--#ifdef __cplusplus
--}
--#endif
--
--#endif
-diff --git a/io/dev-ino.h b/io/dev-ino.h
-deleted file mode 100644
-index 9b1878c79f2eabaf..0000000000000000
---- a/io/dev-ino.h
-+++ /dev/null
-@@ -1,44 +0,0 @@
--/* A simple (device, inode) struct.
--   Copyright (C) 2003-2026 Free Software Foundation, Inc.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--/* Written by Jim Meyering, 2003.  */
--
--#ifndef DEV_INO_H
--#define DEV_INO_H 1
--
--#include <sys/types.h>
--#include <sys/stat.h>
--
--#ifdef __cplusplus
--extern "C" {
--#endif
--
--#ifndef INO_T
--#define INO_T ino_t
--#endif
--
--struct dev_ino
--{
--  INO_T st_ino;
--  dev_t st_dev;
--};
--
--
--#ifdef __cplusplus
--}
--#endif
--
--#endif
-diff --git a/io/fts-cycle.c b/io/fts-cycle.c
-deleted file mode 100644
-index 6bbc9f94460595cb..0000000000000000
---- a/io/fts-cycle.c
-+++ /dev/null
-@@ -1,162 +0,0 @@
--/* Detect cycles in file tree walks.
--
--   Copyright (C) 2003-2006, 2009-2026 Free Software Foundation, Inc.
--
--   Written by Jim Meyering.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--#include "cycle-check.h"
--#include "hash.h"
--
--#ifndef FTS_OPEN
--# define FTSOBJ FTS
--# define FTSENTRY FTSENT
--#endif
--
--/* Use each of these to map a device/inode pair to an FTSENT.  */
--struct Active_dir
--{
--  dev_t dev;
--  INO_T ino;
--  FTSENTRY *fts_ent;
--};
--
--static bool
--AD_compare (void const *x, void const *y)
--{
--  struct Active_dir const *ax = x;
--  struct Active_dir const *ay = y;
--  return ax->ino == ay->ino
--      && ax->dev == ay->dev;
--}
--
--static size_t
--AD_hash (void const *x, size_t table_size)
--{
--  struct Active_dir const *ax = x;
--  return (uintmax_t) ax->ino % table_size;
--}
--
--/* Set up the cycle-detection machinery.  */
--
--static bool
--setup_dir (FTSOBJ *fts)
--{
--  if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
--    {
--      enum { HT_INITIAL_SIZE = 31 };
--      fts->fts_cycle.ht = hash_initialize (HT_INITIAL_SIZE, NULL, AD_hash,
--                                           AD_compare, free);
--      if (! fts->fts_cycle.ht)
--        return false;
--    }
--  else
--    {
--      fts->fts_cycle.state = malloc (sizeof *fts->fts_cycle.state);
--      if (! fts->fts_cycle.state)
--        return false;
--      cycle_check_init (fts->fts_cycle.state);
--    }
--
--  return true;
--}
--
--/* Enter a directory during a file tree walk.  */
--
--static bool
--enter_dir (FTSOBJ *fts, FTSENTRY *ent)
--{
--  if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
--    {
--      struct Active_dir *ad = malloc (sizeof *ad);
--      if (!ad)
--        return false;
--
--      struct STRUCT_STAT const *st = ent->fts_statp;
--      ad->dev = st->st_dev;
--      ad->ino = st->st_ino;
--      ad->fts_ent = ent;
--
--      /* See if we've already encountered this directory.
--         This can happen when following symlinks as well as
--         with a corrupted directory hierarchy. */
--      struct Active_dir *ad_from_table = hash_insert (fts->fts_cycle.ht, ad);
--
--      if (ad_from_table != ad)
--        {
--          free (ad);
--          if (!ad_from_table)
--            return false;
--
--          /* There was an entry with matching dev/inode already in the table.
--             Record the fact that we've found a cycle.  */
--          ent->fts_cycle = ad_from_table->fts_ent;
--          ent->fts_info = FTS_DC;
--        }
--    }
--  else
--    {
--      if (cycle_check (fts->fts_cycle.state, ent->fts_statp))
--        {
--          /* FIXME: setting fts_cycle like this isn't proper.
--             To do what the documentation requires, we'd have to
--             go around the cycle again and find the right entry.
--             But no callers in coreutils use the fts_cycle member. */
--          ent->fts_cycle = ent;
--          ent->fts_info = FTS_DC;
--        }
--    }
--
--  return true;
--}
--
--/* Leave a directory during a file tree walk.  */
--
--static void
--leave_dir (FTSOBJ *fts, FTSENTRY *ent)
--{
--  struct STRUCT_STAT const *st = ent->fts_statp;
--  if (fts->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
--    {
--      struct Active_dir obj;
--      obj.dev = st->st_dev;
--      obj.ino = st->st_ino;
--      void *found = hash_remove (fts->fts_cycle.ht, &obj);
--      if (!found)
--        abort ();
--      free (found);
--    }
--  else
--    {
--      FTSENTRY *parent = ent->fts_parent;
--      if (parent != NULL && 0 <= parent->fts_level)
--        CYCLE_CHECK_REFLECT_CHDIR_UP (fts->fts_cycle.state,
--                                      *(parent->fts_statp), *st);
--    }
--}
--
--/* Free any memory used for cycle detection.  */
--
--static void
--free_dir (FTSOBJ *sp)
--{
--  if (sp->fts_options & (FTS_TIGHT_CYCLE_CHECK | FTS_LOGICAL))
--    {
--      if (sp->fts_cycle.ht)
--        hash_free (sp->fts_cycle.ht);
--    }
--  else
--    free (sp->fts_cycle.state);
--}
-diff --git a/io/fts.c b/io/fts.c
-index 3825f0aeb4eb1594..27a15b110431ce28 100644
---- a/io/fts.c
-+++ b/io/fts.c
-@@ -1,23 +1,24 @@
--/* Traverse a file hierarchy.
-+/* File tree traversal functions.
-+   Copyright (C) 1994-2026 Free Software Foundation, Inc.
-+   This file is part of the GNU C Library.
- 
--   Copyright (C) 2004-2026 Free Software Foundation, Inc.
-+   The GNU C Library is free software; you can redistribute it and/or
-+   modify it under the terms of the GNU Lesser General Public
-+   License as published by the Free Software Foundation; either
-+   version 2.1 of the License, or (at your option) any later version.
- 
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file is distributed in the hope that it will be useful,
-+   The GNU C Library 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 Lesser General Public License for more details.
-+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+   Lesser General Public License for more details.
- 
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
-+   You should have received a copy of the GNU Lesser General Public
-+   License along with the GNU C Library; if not, see
-+   <https://www.gnu.org/licenses/>.  */
- 
- /*-
-  * Copyright (c) 1990, 1993, 1994
-- *      The Regents of the University of California.  All rights reserved.
-+ *	The Regents of the University of California.  All rights reserved.
-  *
-  * Redistribution and use in source and binary forms, with or without
-  * modification, are permitted provided that the following conditions
-@@ -31,7 +32,7 @@
-  *    may be used to endorse or promote products derived from this software
-  *    without specific prior written permission.
-  *
-- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
-+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
-  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
-@@ -44,1122 +45,457 @@
-  * SUCH DAMAGE.
-  */
- 
--#include <config.h>
--
--#if defined LIBC_SCCS && !defined GCC_LINT && !defined lint
--static char sccsid[] = "@(#)fts.c       8.6 (Berkeley) 8/14/94";
--#endif
-+#if defined(LIBC_SCCS) && !defined(lint)
-+static char sccsid[] = "@(#)fts.c	8.6 (Berkeley) 8/14/94";
-+#endif /* LIBC_SCCS and not lint */
- 
--#if _LIBC
--# include <fts.h>
--#else
--# include "fts_.h"
--#endif
--#if _LIBC || HAVE_SYS_PARAM_H
--# include <sys/param.h>
--#endif
--#include <sys/stat.h>
-+#include <sys/param.h>
-+#include <include/sys/stat.h>
- #include <fcntl.h>
-+#include <dirent.h>
- #include <errno.h>
--#include <stddef.h>
-+#include <fts.h>
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- 
-+
-+/* Largest alignment size needed, minus one.
-+   Usually long double is the worst case.  */
-+#ifndef ALIGNBYTES
-+#define ALIGNBYTES	(__alignof__ (long double) - 1)
-+#endif
-+/* Align P to that size.  */
-+#ifndef ALIGN
-+#define	ALIGN(p)	(((uintptr_t) (p) + ALIGNBYTES) & ~ALIGNBYTES)
-+#endif
-+
-+
- /* Support for the LFS API version.  */
- #ifndef FTS_OPEN
--# define FTS_OPEN fts_open
--# define FTS_CLOSE fts_close
--# define FTS_READ fts_read
--# define FTS_SET fts_set
--# define FTS_CHILDREN fts_children
-+#define FTS_OPEN fts_open
-+#define FTS_CLOSE fts_close
-+#define FTS_READ fts_read
-+#define FTS_SET fts_set
-+#define FTS_CHILDREN fts_children
- # define FTSOBJ FTS
- # define FTSENTRY FTSENT
- # define INO_T ino_t
- # define STRUCT_STAT stat
-+# define STAT __stat
-+# define LSTAT __lstat
- # define FSTAT __fstat
--# define FSTATAT __fstatat
--# define STRUCT_STATFS statfs
--# define FSTATFS __fstatfs
--#endif
--
--#if ! _LIBC
--# include "attribute.h"
--# include "fcntl--.h"
--# include "openat.h"
--# include "opendirat.h"
--# include "same-inode.h"
--# define OPENDIRAT opendirat
--# define FTSENT_WRAPPER(__p) __p
--# define FTS_COMPAR_CAST(__fn) __fn
--#else
--# include <stdbool.h>
--
--# define internal_function
--# define FALLTHROUGH               ; [[fallthrough]]
--# define HAVE_STRUCT_DIRENT_D_TYPE 1
--# define GNULIB_FTS_DEBUG          0
--# ifdef O_PATH
--#  define O_SEARCH                 O_PATH
--# else
--#  define O_SEARCH                 O_RDONLY
--# endif
--# define HAVE_SYS_VFS_H            1
--# define HAVE_FSTATFS              1
--# define HAVE_STRUCT_STATFS_F_TYPE 1
--# define HAVE_OPENAT               1
--# define HAVE_WORKING_O_NOFOLLOW   1
--# define _GL_CMP(a, b)             ((a) < (b) ? -1 : (a) > (b))
--# define OPENDIRAT                 __opendirat
--
--static inline bool openat_needs_fchdir (void)
--{
--  return false;
--}
--
--static inline bool streq (const char *s1, const char *s2)
--{
--  return strcmp (s1, s2) == 0;
--}
--# define reallocarray              __libc_reallocarray
--# define fchdir                    __fchdir
--# define close                     __close
--# define closedir                  __closedir
--# define fcntl                     __fcntl
--# define readdir                   __readdir
--# ifndef dirfd
--#  define dirfd                    __dirfd
--# endif
--# define open                      __open
--# define openat                    __openat
--
--# include "cycle-check.c"
--# include "i-ring.c"
--
--struct FTSENT_wrapper
--{
--  FTSOBJ *fts_fts;                /* the file hierarchy itself */
--  DIR *fts_dirp;                  /* Dir pointer for any directory containing
--				     more entries than we read at one time.  */
--  struct STRUCT_STAT fts_stat;
--
--  FTSENTRY ent;
--};
--
--/* glibc historicaly defines the FTS::fts_compar as having 'void *', while the
--   fts_open has a function point using 'FTSENT **' as argument.  */
--# define FTS_COMPAR_CAST(__fn) ((int (*) (void const *, void const *))__fn)
--
--# define FTSENT_WRAPPER(p) \
--    ((struct FTSENT_wrapper *) ((char *)(p) - offsetof(struct FTSENT_wrapper, ent)))
--#endif
--#define FTSENT_FTS(p)   (FTSENT_WRAPPER(p)->fts_fts)
--#define FTSENT_DIRP(p)  (FTSENT_WRAPPER(p)->fts_dirp)
--
--#include "flexmember.h"
--
--#include <dirent.h>
--#ifndef _D_EXACT_NAMLEN
--# define _D_EXACT_NAMLEN(dirent) strlen ((dirent)->d_name)
--#endif
--
--#if HAVE_STRUCT_DIRENT_D_TYPE
--/* True if the type of the directory entry D is known.  */
--# define DT_IS_KNOWN(d) ((d)->d_type != DT_UNKNOWN)
--/* True if the type of the directory entry D must be T.  */
--# define DT_MUST_BE(d, t) ((d)->d_type == (t))
--# define D_TYPE(d) ((d)->d_type)
--#else
--# define DT_IS_KNOWN(d) false
--# define DT_MUST_BE(d, t) false
--# define D_TYPE(d) DT_UNKNOWN
--
--# undef DT_UNKNOWN
--# define DT_UNKNOWN 0
--
--/* Any nonzero values will do here, so long as they're distinct.
--   Undef any existing macros out of the way.  */
--# undef DT_BLK
--# undef DT_CHR
--# undef DT_DIR
--# undef DT_FIFO
--# undef DT_LNK
--# undef DT_REG
--# undef DT_SOCK
--# define DT_BLK 1
--# define DT_CHR 2
--# define DT_DIR 3
--# define DT_FIFO 4
--# define DT_LNK 5
--# define DT_REG 6
--# define DT_SOCK 7
--#endif
--
--#ifndef S_IFBLK
--# define S_IFBLK 0
--#endif
--#ifndef S_IFLNK
--# define S_IFLNK 0
--#endif
--#ifndef S_IFSOCK
--# define S_IFSOCK 0
--#endif
--
--enum
--{
--  NOT_AN_INODE_NUMBER = 0
--};
--
--#ifdef D_INO_IN_DIRENT
--# define D_INO(dp) (dp)->d_ino
--#else
--/* Some systems don't have inodes, so fake them to avoid lots of ifdefs.  */
--# define D_INO(dp) NOT_AN_INODE_NUMBER
--#endif
--
--/* If possible (see max_entries, below), read no more than this many directory
--   entries at a time.  Without this limit (i.e., when using non-NULL
--   fts_compar), processing a directory with 4,000,000 entries requires ~1GiB
--   of memory, and handling 64M entries would require 16GiB of memory.  */
--#ifndef FTS_MAX_READDIR_ENTRIES
--# define FTS_MAX_READDIR_ENTRIES 100000
--#endif
--
--/* If there are more than this many entries in a directory,
--   and the conditions mentioned below are satisfied, then sort
--   the entries on inode number before any further processing.  */
--#ifndef FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
--# define FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD 10000
--#endif
--
--enum
--{
--  _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD = FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
--};
--
--enum Fts_stat
--{
--  FTS_NO_STAT_REQUIRED = 1,
--  FTS_STAT_REQUIRED = 2
--};
--
--#ifndef __set_errno
--# define __set_errno(Val) errno = (Val)
--#endif
--
--/* If this host provides the openat function, then we can avoid
--   attempting to open "." in some initialization code below.  */
--#ifdef HAVE_OPENAT
--# define HAVE_OPENAT_SUPPORT 1
--#else
--# define HAVE_OPENAT_SUPPORT 0
--#endif
--
--#ifdef NDEBUG
--# define fts_assert(expr) ((void) (0 && (expr)))
--#else
--# define fts_assert(expr)       \
--    do                          \
--      {                         \
--        if (!(expr))            \
--          abort ();             \
--      }                         \
--    while (false)
- #endif
- 
--static FTSENTRY  *fts_alloc (FTSOBJ *, const char *, size_t);
--static FTSENTRY  *fts_build (FTSOBJ *, int);
--static void      fts_lfree (FTSENTRY *);
--static void      fts_load (FTSOBJ *, FTSENTRY *);
--static size_t    fts_maxarglen (char * const *);
--static void      fts_padjust (FTSOBJ *, FTSENTRY *);
--static bool      fts_palloc (FTSOBJ *, size_t);
--static FTSENTRY  *fts_sort (FTSOBJ *, FTSENTRY *, size_t);
--static unsigned short int fts_stat (FTSOBJ *, FTSENTRY *, bool);
-+static FTSENTRY	*fts_alloc (FTSOBJ *, const char *, size_t);
-+static FTSENTRY	*fts_build (FTSOBJ *, int);
-+static void	 fts_lfree (FTSENTRY *);
-+static void	 fts_load (FTSOBJ *, FTSENTRY *);
-+static size_t	 fts_maxarglen (char * const *);
-+static void	 fts_padjust (FTSOBJ *, FTSENTRY *);
-+static int	 fts_palloc (FTSOBJ *, size_t);
-+static FTSENTRY	*fts_sort (FTSOBJ *, FTSENTRY *, int);
-+static u_short	 fts_stat (FTSOBJ *, FTSENTRY *, int);
- static int      fts_safe_changedir (FTSOBJ *, FTSENTRY *, int, const char *);
- 
--#include "fts-cycle.c"
--
- #ifndef MAX
--# define MAX(a,b) ((a) > (b) ? (a) : (b))
--#endif
--
--#ifndef SIZE_MAX
--# define SIZE_MAX ((size_t) -1)
-+#define MAX(a, b)	({ __typeof__ (a) _a = (a); \
-+			   __typeof__ (b) _b = (b); \
-+			   _a > _b ? _a : _b; })
- #endif
- 
--#define ISDOT(a)        (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
-+#define	ISDOT(a)	(a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
- 
--#define CLR(opt)        (sp->fts_options &= ~(opt))
--#define ISSET(opt)      ((sp->fts_options & (opt)) != 0)
--#define SET(opt)        (sp->fts_options |= (opt))
--
--/* FIXME: FTS_NOCHDIR is now misnamed.
--   Call it FTS_USE_FULL_RELATIVE_FILE_NAMES instead. */
--#define FCHDIR(sp, fd)                                  \
--  (!ISSET(FTS_NOCHDIR) && (ISSET(FTS_CWDFD)             \
--                           ? (cwd_advance_fd ((sp), (fd), true), 0) \
--                           : fchdir (fd)))
-+#define CLR(opt)	(sp->fts_options &= ~(opt))
-+#define	ISSET(opt)	(sp->fts_options & (opt))
-+#define	SET(opt)	(sp->fts_options |= (opt))
- 
-+#define	FCHDIR(sp, fd)	(!ISSET(FTS_NOCHDIR) && __fchdir(fd))
- 
- /* fts_build flags */
--/* FIXME: make this an enum */
--#define BCHILD          1               /* fts_children */
--#define BNAMES          2               /* fts_children, names only */
--#define BREAD           3               /* fts_read */
--
--#if GNULIB_FTS_DEBUG
--# include <inttypes.h>
--# include <stdio.h>
--bool fts_debug = false;
--# define Dprintf(x) do { if (fts_debug) printf x; } while (false)
--static void fd_ring_check (FTSOBJ const *);
--static void fd_ring_print (FTSOBJ const *, FILE *, char const *);
--#else
--# define Dprintf(x)
--# define fd_ring_check(x)
--# define fd_ring_print(a, b, c)
--#endif
-+#define	BCHILD		1		/* fts_children */
-+#define	BNAMES		2		/* fts_children, names only */
-+#define	BREAD		3		/* fts_read */
- 
--#define LEAVE_DIR(Fts, Ent, Tag)                                \
--  do                                                            \
--    {                                                           \
--      Dprintf (("  %s-leaving: %s\n", Tag, (Ent)->fts_path));   \
--      leave_dir (Fts, Ent);                                     \
--      fd_ring_check (Fts);                                      \
--    }                                                           \
--  while (false)
--
--static void
--fd_ring_clear (I_ring *fd_ring)
--{
--  while ( ! i_ring_empty (fd_ring))
--    {
--      int fd = i_ring_pop (fd_ring);
--      if (0 <= fd)
--        close (fd);
--    }
--}
--
--/* Overload the fts_statp->st_size member (otherwise unused, when
--   fts_info is FTS_NSOK) to indicate whether fts_read should stat
--   this entry or not.  */
--static void
--fts_set_stat_required (FTSENTRY *p, bool required)
-+FTSOBJ *
-+FTS_OPEN (char * const *argv, int options,
-+	  int (*compar) (const FTSENTRY **, const FTSENTRY **))
- {
--  fts_assert (p->fts_info == FTS_NSOK);
--  p->fts_statp->st_size = (required
--                           ? FTS_STAT_REQUIRED
--                           : FTS_NO_STAT_REQUIRED);
--}
-+	FTSOBJ *sp;
-+	FTSENTRY *p, *root;
-+	int nitems;
-+	FTSENTRY *parent = NULL;
-+	FTSENTRY *tmp;
-+
-+	/* Options check. */
-+	if (options & ~FTS_OPTIONMASK) {
-+		__set_errno (EINVAL);
-+		return (NULL);
-+	}
- 
--/* Virtual fchdir.  Advance SP's working directory file descriptor,
--   SP->fts_cwd_fd, to FD, and push the previous value onto the fd_ring.
--   CHDIR_DOWN_ONE is true if FD corresponds to an entry in the directory
--   open on sp->fts_cwd_fd; i.e., to move the working directory one level
--   down.  */
--static void
--internal_function
--cwd_advance_fd (FTSOBJ *sp, int fd, bool chdir_down_one)
--{
--  int old = sp->fts_cwd_fd;
--  fts_assert (old != fd || old == AT_FDCWD);
--
--  if (chdir_down_one)
--    {
--      /* Push "old" onto the ring.
--         If the displaced file descriptor is non-negative, close it.  */
--      int prev_fd_in_slot = i_ring_push (&sp->fts_fd_ring, old);
--      fd_ring_print (sp, stderr, "post-push");
--      if (0 <= prev_fd_in_slot)
--        close (prev_fd_in_slot); /* ignore any close failure */
--    }
--  else if ( ! ISSET (FTS_NOCHDIR))
--    {
--      if (0 <= old)
--        close (old); /* ignore any close failure */
--    }
--
--  sp->fts_cwd_fd = fd;
--}
-+	/* Allocate/initialize the stream */
-+	if ((sp = malloc((u_int)sizeof(FTSOBJ))) == NULL)
-+		return (NULL);
-+	memset(sp, 0, sizeof(FTSOBJ));
-+	sp->fts_compar = (int (*) (const void *, const void *)) compar;
-+	sp->fts_options = options;
- 
--/* Restore the initial, pre-traversal, "working directory".
--   In FTS_CWDFD mode, we merely call cwd_advance_fd, otherwise,
--   we may actually change the working directory.
--   Return 0 upon success. Upon failure, set errno and return nonzero.  */
--static int
--restore_initial_cwd (FTSOBJ *sp)
--{
--  int fail = FCHDIR (sp, ISSET (FTS_CWDFD) ? AT_FDCWD : sp->fts_rfd);
--  fd_ring_clear (&(sp->fts_fd_ring));
--  return fail;
--}
-+	/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
-+	if (ISSET(FTS_LOGICAL))
-+		SET(FTS_NOCHDIR);
- 
--/* Open the directory DIR if possible, and return a file
--   descriptor.  Return -1 and set errno on failure.  It doesn't matter
--   whether the file descriptor has read or write access.  */
-+	/*
-+	 * Start out with 1K of path space, and enough, in any case,
-+	 * to hold the user's paths.
-+	 */
-+#ifndef MAXPATHLEN
-+#define MAXPATHLEN 1024
-+#endif
-+	size_t maxarglen = fts_maxarglen(argv);
-+	if (fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
-+		goto mem1;
-+
-+	/* Allocate/initialize root's parent. */
-+	if (*argv != NULL) {
-+		if ((parent = fts_alloc(sp, "", 0)) == NULL)
-+			goto mem2;
-+		parent->fts_level = FTS_ROOTPARENTLEVEL;
-+	  }
-+
-+	/* Allocate/initialize root(s). */
-+	for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
-+		/* Don't allow zero-length paths. */
-+		size_t len = strlen(*argv);
-+		if (len == 0) {
-+			__set_errno (ENOENT);
-+			goto mem3;
-+		}
-+
-+		p = fts_alloc(sp, *argv, len);
-+		p->fts_level = FTS_ROOTLEVEL;
-+		p->fts_parent = parent;
-+		p->fts_accpath = p->fts_name;
-+		p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
-+
-+		/* Command-line "." and ".." are real directories. */
-+		if (p->fts_info == FTS_DOT)
-+			p->fts_info = FTS_D;
-+
-+		/*
-+		 * If comparison routine supplied, traverse in sorted
-+		 * order; otherwise traverse in the order specified.
-+		 */
-+		if (compar) {
-+			p->fts_link = root;
-+			root = p;
-+		} else {
-+			p->fts_link = NULL;
-+			if (root == NULL)
-+				tmp = root = p;
-+			else {
-+				tmp->fts_link = p;
-+				tmp = p;
-+			}
-+		}
-+	}
-+	if (compar && nitems > 1)
-+		root = fts_sort(sp, root, nitems);
- 
--static int
--internal_function
--diropen (FTSOBJ const *sp, char const *dir)
--{
--  int open_flags = (O_SEARCH | O_CLOEXEC | O_DIRECTORY | O_NOCTTY | O_NONBLOCK
--                    | (ISSET (FTS_PHYSICAL) ? O_NOFOLLOW : 0));
-+	/*
-+	 * Allocate a dummy pointer and make fts_read think that we've just
-+	 * finished the node before the root(s); set p->fts_info to FTS_INIT
-+	 * so that everything about the "current" node is ignored.
-+	 */
-+	if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
-+		goto mem3;
-+	sp->fts_cur->fts_link = root;
-+	sp->fts_cur->fts_info = FTS_INIT;
- 
--  int fd = (ISSET (FTS_CWDFD)
--            ? openat (sp->fts_cwd_fd, dir, open_flags)
--            : open (dir, open_flags));
--  return fd;
--}
-+	/*
-+	 * If using chdir(2), grab a file descriptor pointing to dot to ensure
-+	 * that we can get back here; this could be avoided for some paths,
-+	 * but almost certainly not worth the effort.  Slashes, symbolic links,
-+	 * and ".." are all fairly nasty problems.  Note, if we can't get the
-+	 * descriptor we run anyway, just more slowly.
-+	 */
-+	if (!ISSET(FTS_NOCHDIR)
-+	    && (sp->fts_rfd = __open(".", O_RDONLY, 0)) < 0)
-+		SET(FTS_NOCHDIR);
- 
--FTSOBJ *
--FTS_OPEN (char * const *argv,
--          register int options,
--          int (*compar) (const FTSENTRY **, const FTSENTRY **))
--{
--        /* Options check: glibc added other flags after FTS_NAMEONLY and
--	   FTS_STOP, and they are assumed to be private.  */
--        if (options & ~FTS_OPTIONMASK
--#if _LIBC
--	    || options & (FTS_NAMEONLY | FTS_STOP)
--#endif
--	    ) {
--                __set_errno (EINVAL);
--                return (NULL);
--        }
--        if ((options & FTS_NOCHDIR) && (options & FTS_CWDFD)) {
--                __set_errno (EINVAL);
--                return (NULL);
--        }
--#if !_LIBC
--        if ( ! (options & (FTS_LOGICAL | FTS_PHYSICAL))) {
--                __set_errno (EINVAL);
--                return (NULL);
--        }
--#else
--	/* glibc historically falls to FTS_PHYSICAL if no FTS_PHYSICAL or
--	   FTS_LOGICAL is specified.  */
--        if (! (options & (FTS_PHYSICAL | FTS_LOGICAL)))
--	  options |= FTS_PHYSICAL;
--#endif
-+	return (sp);
- 
--        /* Allocate/initialize the stream */
--        register FTSOBJ *sp = calloc (1, sizeof *sp);
--        if (sp == NULL)
--                return (NULL);
--        sp->fts_compar = FTS_COMPAR_CAST(compar);
--        sp->fts_options = options;
--
--        /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
--        if (ISSET(FTS_LOGICAL)) {
--                SET(FTS_NOCHDIR);
--                CLR(FTS_CWDFD);
--        }
--
--        /* Initialize fts_cwd_fd.  */
--        sp->fts_cwd_fd = AT_FDCWD;
--        if ( ISSET(FTS_CWDFD) && ! HAVE_OPENAT_SUPPORT)
--          {
--            /* While it isn't technically necessary to open "." this
--               early, doing it here saves us the trouble of ensuring
--               later (where it'd be messier) that "." can in fact
--               be opened.  If not, revert to FTS_NOCHDIR mode.  */
--            int fd = open (".", O_SEARCH | O_CLOEXEC);
--            if (fd < 0)
--              {
--                /* Even if "." is unreadable, don't revert to FTS_NOCHDIR mode
--                   on systems like Linux+PROC_FS, where our openat emulation
--                   is good enough.  Note: on a system that emulates
--                   openat via /proc, this technique can still fail, but
--                   only in extreme conditions, e.g., when the working
--                   directory cannot be saved (i.e. save_cwd fails) --
--                   and that happens on Linux only when "." is unreadable
--                   and the CWD would be longer than PATH_MAX.
--                   FIXME: once Linux kernel openat support is well established,
--                   replace the above open call and this entire if/else block
--                   with the body of the if-block below.  */
--                if ( openat_needs_fchdir ())
--                  {
--                    SET(FTS_NOCHDIR);
--                    CLR(FTS_CWDFD);
--                  }
--              }
--            else
--              {
--                close (fd);
--              }
--          }
--
--        /*
--         * Start out with 1K of file name space, and enough, in any case,
--         * to hold the user's file names.
--         */
--#ifndef MAXPATHLEN
--# define MAXPATHLEN 1024
--#endif
--        {
--          size_t maxarglen = fts_maxarglen(argv);
--          if (! fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
--                  goto mem1;
--        }
--
--        /* Allocate/initialize root's parent. */
--        FTSENTRY *parent = NULL;
--        if (*argv != NULL) {
--                if ((parent = fts_alloc(sp, "", 0)) == NULL)
--                        goto mem2;
--                parent->fts_level = FTS_ROOTPARENTLEVEL;
--          }
--
--        /* The classic fts implementation would call fts_stat with
--           a new entry for each iteration of the loop below.
--           If the comparison function is not specified or if the
--           FTS_DEFER_STAT option is in effect, don't stat any entry
--           in this loop.  This is an attempt to minimize the interval
--           between the initial stat/lstat/fstatat and the point at which
--           a directory argument is first opened.  This matters for any
--           directory command line argument that resides on a file system
--           without genuine i-nodes.  If you specify FTS_DEFER_STAT along
--           with a comparison function, that function must not access any
--           data via the fts_statp pointer.  */
--        bool defer_stat = (compar == NULL || ISSET(FTS_DEFER_STAT));
--
--        /* Allocate/initialize root(s). */
--        register FTSENTRY *root;
--        register size_t nitems;
--        FTSENTRY *tmp = NULL;     /* pacify gcc */
--        for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
--                /* *Do* allow zero-length file names. */
--                size_t len = strlen(*argv);
--
--                if ( ! (options & FTS_VERBATIM))
--                  {
--                    /* If there are two or more trailing slashes, trim all but one,
--                       but don't change "//" to "/", and do map "///" to "/".  */
--                    char const *v = *argv;
--                    if (2 < len && v[len - 1] == '/')
--                      while (1 < len && v[len - 2] == '/')
--                        --len;
--                  }
--
--                register FTSENTRY *p = fts_alloc(sp, *argv, len);
--                if (p == NULL)
--                        goto mem3;
--                p->fts_level = FTS_ROOTLEVEL;
--                p->fts_parent = parent;
--                p->fts_accpath = p->fts_name;
--                /* Even when defer_stat is true, be sure to stat the first
--                   command line argument, since fts_read (at least with
--                   FTS_XDEV) requires that.  */
--                if (defer_stat && root != NULL) {
--                        p->fts_info = FTS_NSOK;
--                        fts_set_stat_required(p, true);
--                } else {
--                        p->fts_info = fts_stat(sp, p, false);
--                }
--
--                /*
--                 * If comparison routine supplied, traverse in sorted
--                 * order; otherwise traverse in the order specified.
--                 */
--                if (compar) {
--                        p->fts_link = root;
--                        root = p;
--                } else {
--                        p->fts_link = NULL;
--                        if (root == NULL)
--                                tmp = root = p;
--                        else {
--                                tmp->fts_link = p;
--                                tmp = p;
--                        }
--                }
--        }
--        if (compar && nitems > 1)
--                root = fts_sort(sp, root, nitems);
--
--        /*
--         * Allocate a dummy pointer and make fts_read think that we've just
--         * finished the node before the root(s); set p->fts_info to FTS_INIT
--         * so that everything about the "current" node is ignored.
--         */
--        if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
--                goto mem3;
--        sp->fts_cur->fts_link = root;
--        sp->fts_cur->fts_info = FTS_INIT;
--        sp->fts_cur->fts_level = 1;
--        if (! setup_dir (sp))
--                goto mem3;
--
--        /*
--         * If using chdir(2), grab a file descriptor pointing to dot to ensure
--         * that we can get back here; this could be avoided for some file names,
--         * but almost certainly not worth the effort.  Slashes, symbolic links,
--         * and ".." are all fairly nasty problems.  Note, if we can't get the
--         * descriptor we run anyway, just more slowly.
--         */
--        if (!ISSET(FTS_NOCHDIR) && !ISSET(FTS_CWDFD)
--            && (sp->fts_rfd = diropen (sp, ".")) < 0)
--                SET(FTS_NOCHDIR);
--
--        i_ring_init (&sp->fts_fd_ring, -1);
--        return (sp);
--
--mem3:   fts_lfree(root);
--        free(FTSENT_WRAPPER(parent));
--mem2:   free(sp->fts_path);
--mem1:   free(sp);
--        return (NULL);
-+mem3:	fts_lfree(root);
-+	free(parent);
-+mem2:	free(sp->fts_path);
-+mem1:	free(sp);
-+	return (NULL);
- }
- 
- static void
--internal_function
--fts_load (FTSOBJ *sp, register FTSENTRY *p)
-+fts_load (FTSOBJ *sp, FTSENTRY *p)
- {
--        /*
--         * Load the stream structure for the next traversal.  Since we don't
--         * actually enter the directory until after the preorder visit, set
--         * the fts_accpath field specially so the chdir gets done to the right
--         * place and the user can access the first node.  From fts_open it's
--         * known that the file name will fit.
--         */
--        register size_t len = p->fts_pathlen = p->fts_namelen;
--        memmove(sp->fts_path, p->fts_name, len + 1);
--        register char *cp = strrchr(p->fts_name, '/');
--        if (cp && (cp != p->fts_name || cp[1])) {
--                len = strlen(++cp);
--                memmove(p->fts_name, cp, len + 1);
--                p->fts_namelen = len;
--        }
--        p->fts_accpath = p->fts_path = sp->fts_path;
-+	int len;
-+	char *cp;
-+
-+	/*
-+	 * Load the stream structure for the next traversal.  Since we don't
-+	 * actually enter the directory until after the preorder visit, set
-+	 * the fts_accpath field specially so the chdir gets done to the right
-+	 * place and the user can access the first node.  From fts_open it's
-+	 * known that the path will fit.
-+	 */
-+	len = p->fts_pathlen = p->fts_namelen;
-+	memmove(sp->fts_path, p->fts_name, len + 1);
-+	if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
-+		len = strlen(++cp);
-+		memmove(p->fts_name, cp, len + 1);
-+		p->fts_namelen = len;
-+	}
-+	p->fts_accpath = p->fts_path = sp->fts_path;
-+	sp->fts_dev = p->fts_dev;
- }
- 
- int
- FTS_CLOSE (FTSOBJ *sp)
- {
--        /*
--         * This still works if we haven't read anything -- the dummy structure
--         * points to the root list, so we step through to the end of the root
--         * list which has a valid parent pointer.
--         */
--        if (sp->fts_cur) {
--                register FTSENTRY *p;
--                for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
--                        register FTSENTRY *freep = p;
--                        p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
--                        free(FTSENT_WRAPPER(freep));
--                }
--                free(FTSENT_WRAPPER(p));
--        }
--
--        /* Free up child linked list, sort array, file name buffer. */
--        if (sp->fts_child)
--                fts_lfree(sp->fts_child);
--        free(sp->fts_array);
--        free(sp->fts_path);
--
--        int saved_errno = 0;
--        if (ISSET(FTS_CWDFD))
--          {
--            if (0 <= sp->fts_cwd_fd)
--              if (close (sp->fts_cwd_fd))
--                saved_errno = errno;
--          }
--        else if (!ISSET(FTS_NOCHDIR))
--          {
--            /* Return to original directory, save errno if necessary. */
--            if (fchdir(sp->fts_rfd))
--              saved_errno = errno;
--
--            /* If close fails, record errno only if saved_errno is zero,
--               so that we report the probably-more-meaningful fchdir errno.  */
--            if (close (sp->fts_rfd))
--              if (saved_errno == 0)
--                saved_errno = errno;
--          }
--
--        fd_ring_clear (&sp->fts_fd_ring);
--
--        if (sp->fts_leaf_optimization_works_ht)
--          hash_free (sp->fts_leaf_optimization_works_ht);
--
--        free_dir (sp);
--
--        /* Free up the stream pointer. */
--        free(sp);
--
--        /* Set errno and return. */
--        if (saved_errno) {
--                __set_errno (saved_errno);
--                return (-1);
--        }
--
--        return (0);
--}
-+	FTSENTRY *freep, *p;
-+	int saved_errno;
- 
--/* Minimum link count of a traditional Unix directory.  When leaf
--   optimization is OK and a directory's st_nlink == MIN_DIR_NLINK,
--   then the directory has no subdirectories.  */
--enum { MIN_DIR_NLINK = 2 };
--
--/* Whether leaf optimization is OK for a directory.  */
--enum leaf_optimization
--  {
--    /* st_nlink is not reliable for this directory's subdirectories.  */
--    NO_LEAF_OPTIMIZATION,
--
--    /* st_nlink == 2 means the directory lacks subdirectories.  */
--    OK_LEAF_OPTIMIZATION
--  };
--
--#if (defined __linux__ || defined __ANDROID__) \
--  && HAVE_SYS_VFS_H && HAVE_FSTATFS && HAVE_STRUCT_STATFS_F_TYPE
--
--# include <sys/vfs.h>
--
--/* Linux-specific constants from coreutils' src/fs.h */
--# define S_MAGIC_AFS 0x5346414F
--# define S_MAGIC_CIFS 0xFF534D42
--# define S_MAGIC_LUSTRE 0x0BD00BD0
--# define S_MAGIC_NFS 0x6969
--# define S_MAGIC_PROC 0x9FA0
--# define S_MAGIC_TMPFS 0x1021994
--
--# ifdef HAVE___FSWORD_T
--typedef __fsword_t fsword;
--# else
--typedef long int fsword;
--# endif
--
--/* Map a stat.st_dev number to a file system type number f_ftype.  */
--struct dev_type
--{
--  dev_t st_dev;
--  fsword f_type;
--};
--
--/* Use a tiny initial size.  If a traversal encounters more than
--   a few devices, the cost of growing/rehashing this table will be
--   rendered negligible by the number of inodes processed.  */
--enum { DEV_TYPE_HT_INITIAL_SIZE = 13 };
--
--static size_t
--dev_type_hash (void const *x, size_t table_size)
--{
--  struct dev_type const *ax = x;
--  uintmax_t dev = ax->st_dev;
--  return dev % table_size;
--}
--
--static bool
--dev_type_compare (void const *x, void const *y)
--{
--  struct dev_type const *ax = x;
--  struct dev_type const *ay = y;
--  return ax->st_dev == ay->st_dev;
-+	/*
-+	 * This still works if we haven't read anything -- the dummy structure
-+	 * points to the root list, so we step through to the end of the root
-+	 * list which has a valid parent pointer.
-+	 */
-+	if (sp->fts_cur) {
-+		for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
-+			freep = p;
-+			p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
-+			free(freep);
-+		}
-+		free(p);
-+	}
-+
-+	/* Free up child linked list, sort array, path buffer. */
-+	if (sp->fts_child)
-+		fts_lfree(sp->fts_child);
-+	free(sp->fts_array);
-+	free(sp->fts_path);
-+
-+	/* Return to original directory, save errno if necessary. */
-+	if (!ISSET(FTS_NOCHDIR)) {
-+		saved_errno = __fchdir(sp->fts_rfd) ? errno : 0;
-+		(void)__close(sp->fts_rfd);
-+
-+		/* Set errno and return. */
-+		if (saved_errno != 0) {
-+			/* Free up the stream pointer. */
-+			free(sp);
-+			__set_errno (saved_errno);
-+			return (-1);
-+		}
-+	}
-+
-+	/* Free up the stream pointer. */
-+	free(sp);
-+	return (0);
- }
- 
--/* Return the file system type of P with file descriptor FD, or 0 if not known.
--   If FD is negative, P's file descriptor is unavailable.
--   Try to cache known values.  */
-+/*
-+ * Special case of "/" at the end of the path so that slashes aren't
-+ * appended which would cause paths to be written as "....//foo".
-+ */
-+#define	NAPPEND(p)							\
-+	(p->fts_path[p->fts_pathlen - 1] == '/'				\
-+	    ? p->fts_pathlen - 1 : p->fts_pathlen)
- 
--static fsword
--filesystem_type (FTSENTRY const *p, int fd)
-+FTSENTRY *
-+FTS_READ (FTSOBJ *sp)
- {
--  FTSOBJ *sp = FTSENT_FTS(p);
--
--  /* If we're not in CWDFD mode, don't bother with this optimization,
--     since the caller is not serious about performance.  */
--  if (!ISSET (FTS_CWDFD))
--    return 0;
--
--  Hash_table *h = sp->fts_leaf_optimization_works_ht;
--  if (! h)
--    h = sp->fts_leaf_optimization_works_ht
--      = hash_initialize (DEV_TYPE_HT_INITIAL_SIZE, NULL, dev_type_hash,
--                         dev_type_compare, free);
--
--  if (h)
--    {
--      struct dev_type tmp;
--      tmp.st_dev = p->fts_statp->st_dev;
--      struct dev_type *ent = hash_lookup (h, &tmp);
--      if (ent)
--        return ent->f_type;
--    }
--
--  /* Look-up failed.  Query directly and cache the result.  */
--  struct STRUCT_STATFS fs_buf;
--  if (fd < 0 || FSTATFS (fd, &fs_buf) != 0)
--    return 0;
--
--  if (h)
--    {
--      struct dev_type *t2 = malloc (sizeof *t2);
--      if (t2)
--        {
--          t2->st_dev = p->fts_statp->st_dev;
--          t2->f_type = fs_buf.f_type;
--
--          struct dev_type *ent = hash_insert (h, t2);
--          if (ent)
--            fts_assert (ent == t2);
--          else
--            free (t2);
--        }
--    }
--
--  return fs_buf.f_type;
--}
-+	FTSENTRY *p, *tmp;
-+	int instr;
-+	char *t;
-+	int saved_errno;
- 
--/* Return true if sorting dirents on inode numbers is known to improve
--   traversal performance for the directory P with descriptor DIR_FD.
--   Return false otherwise.  When in doubt, return true.
--   DIR_FD is negative if unavailable.  */
--static bool
--dirent_inode_sort_may_be_useful (FTSENTRY const *p, int dir_fd)
--{
--  /* Skip the sort only if we can determine efficiently
--     that skipping it is the right thing to do.
--     The cost of performing an unnecessary sort is negligible,
--     while the cost of *not* performing it can be O(N^2) with
--     a very large constant.  */
--
--  switch (filesystem_type (p, dir_fd))
--    {
--    case S_MAGIC_LUSTRE:
--      /* On Lustre, sorting directory entries interferes with its ability to
--         prefetch file metadata (via statahead).  This would make a command
--         like 'du' around 9 times slower.  See
--         <https://bugs.gnu.org/80106>.  */
--    case S_MAGIC_CIFS:
--    case S_MAGIC_NFS:
--    case S_MAGIC_TMPFS:
--      /* On a file system of any of these types, sorting
--         is unnecessary, and hence wasteful.  */
--      return false;
--
--    default:
--      return true;
--    }
--}
-+	/* If finished or unrecoverable error, return NULL. */
-+	if (sp->fts_cur == NULL || ISSET(FTS_STOP))
-+		return (NULL);
- 
--/* Given an FTS entry P for a directory with descriptor DIR_FD,
--   return whether it is valid to apply leaf optimization.
--   The optimization is valid if a directory's st_nlink value equal
--   to MIN_DIR_NLINK means the directory has no subdirectories.
--   DIR_FD is negative if unavailable.  */
--static enum leaf_optimization
--leaf_optimization (FTSENTRY const *p, int dir_fd)
--{
--  switch (filesystem_type (p, dir_fd))
--    {
--    case 0:
--      /* Leaf optimization is unsafe if the file system type is unknown.  */
--      FALLTHROUGH;
--    case S_MAGIC_AFS:
--      /* Although AFS mount points are not counted in st_nlink, they
--         act like directories.  See <https://bugs.debian.org/143111>.  */
--      FALLTHROUGH;
--    case S_MAGIC_CIFS:
--      /* Leaf optimization causes 'find' to abort.  See
--         <https://lists.gnu.org/r/bug-gnulib/2018-04/msg00015.html>.  */
--      FALLTHROUGH;
--    case S_MAGIC_NFS:
--      /* NFS provides usable dirent.d_type but not necessarily for all entries
--         of large directories, so as per <https://bugzilla.redhat.com/1252549>
--         NFS should return true.  However st_nlink values are not accurate on
--         all implementations as per <https://bugzilla.redhat.com/1299169>.  */
--      FALLTHROUGH;
--    case S_MAGIC_PROC:
--      /* Per <https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=143111> /proc
--         may have bogus stat.st_nlink values.  */
--      return NO_LEAF_OPTIMIZATION;
--
--    default:
--      return OK_LEAF_OPTIMIZATION;
--    }
--}
-+	/* Set current node pointer. */
-+	p = sp->fts_cur;
- 
--#else
--static bool
--dirent_inode_sort_may_be_useful (_GL_UNUSED FTSENTRY const *p,
--                                 _GL_UNUSED int dir_fd)
--{
--  return true;
--}
--static enum leaf_optimization
--leaf_optimization (_GL_UNUSED FTSENTRY const *p, _GL_UNUSED int dir_fd)
--{
--  return NO_LEAF_OPTIMIZATION;
--}
--#endif
-+	/* Save and zero out user instructions. */
-+	instr = p->fts_instr;
-+	p->fts_instr = FTS_NOINSTR;
- 
--/*
-- * Special case of "/" at the end of the file name so that slashes aren't
-- * appended which would cause file names to be written as "....//foo".
-- */
--#define NAPPEND(p)                                                      \
--        (p->fts_path[p->fts_pathlen - 1] == '/'                         \
--            ? p->fts_pathlen - 1 : p->fts_pathlen)
-+	/* Any type of file may be re-visited; re-stat and re-turn. */
-+	if (instr == FTS_AGAIN) {
-+		p->fts_info = fts_stat(sp, p, 0);
-+		return (p);
-+	}
- 
--FTSENTRY *
--FTS_READ (FTSOBJ *sp)
--{
--        /* If finished or unrecoverable error, return NULL. */
--        if (sp->fts_cur == NULL || ISSET(FTS_STOP))
--                return (NULL);
--
--        /* Set current node pointer. */
--        register FTSENTRY *p = sp->fts_cur;
--
--        /* Save and zero out user instructions. */
--        register unsigned short int instr = p->fts_instr;
--        p->fts_instr = FTS_NOINSTR;
--
--        /* Any type of file may be re-visited; re-stat and re-turn. */
--        if (instr == FTS_AGAIN) {
--                p->fts_info = fts_stat(sp, p, false);
--                return (p);
--        }
--        Dprintf (("fts_read: p=%s\n",
--                  p->fts_info == FTS_INIT ? "" : p->fts_path));
--
--        /*
--         * Following a symlink -- SLNONE test allows application to see
--         * SLNONE and recover.  If indirecting through a symlink, have
--         * keep a pointer to current location.  If unable to get that
--         * pointer, follow fails.
--         */
--        if (instr == FTS_FOLLOW &&
--            (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
--                p->fts_info = fts_stat(sp, p, true);
--                if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
--                        if ((p->fts_symfd = diropen (sp, ".")) < 0) {
--                                p->fts_errno = errno;
--                                p->fts_info = FTS_ERR;
--                        } else
--                                p->fts_flags |= FTS_SYMFOLLOW;
--                }
--                goto check_for_dir;
--        }
--
--        /* Directory in pre-order. */
--        if (p->fts_info == FTS_D) {
--                /* If skipped or crossed mount point, do post-order visit. */
--                if (instr == FTS_SKIP ||
--                    (ISSET(FTS_XDEV) && p->fts_statp->st_dev != sp->fts_dev)) {
--                        if (p->fts_flags & FTS_SYMFOLLOW)
--                                (void)close(p->fts_symfd);
--                        if (sp->fts_child) {
--                                fts_lfree(sp->fts_child);
--                                sp->fts_child = NULL;
--                        }
--                        p->fts_info = FTS_DP;
--                        LEAVE_DIR (sp, p, "1");
--                        return (p);
--                }
--
--                /* Rebuild if only read the names and now traversing. */
--                if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
--                        CLR(FTS_NAMEONLY);
--                        fts_lfree(sp->fts_child);
--                        sp->fts_child = NULL;
--                }
--
--                /*
--                 * Cd to the subdirectory.
--                 *
--                 * If have already read and now fail to chdir, whack the list
--                 * to make the names come out right, and set the parent errno
--                 * so the application will eventually get an error condition.
--                 * Set the FTS_DONTCHDIR flag so that when we logically change
--                 * directories back to the parent we don't do a chdir.
--                 *
--                 * If haven't read do so.  If the read fails, fts_build sets
--                 * FTS_STOP or the fts_info field of the node.
--                 */
--                if (sp->fts_child != NULL) {
--                        if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
--                                p->fts_errno = errno;
--                                p->fts_flags |= FTS_DONTCHDIR;
--                                for (p = sp->fts_child; p != NULL;
--                                     p = p->fts_link)
--                                        p->fts_accpath =
--                                            p->fts_parent->fts_accpath;
--                        }
--                } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
--                        if (ISSET(FTS_STOP))
--                                return (NULL);
--                        /* If fts_build's call to fts_safe_changedir failed
--                           because it was not able to fchdir into a
--                           subdirectory, tell the caller.  */
--                        if (p->fts_errno && p->fts_info != FTS_DNR)
--                                p->fts_info = FTS_ERR;
--                        LEAVE_DIR (sp, p, "2");
--                        return (p);
--                }
--                p = sp->fts_child;
--                sp->fts_child = NULL;
--                goto name;
--        }
--
--        /* Move to the next node on this level. */
--next: ;
--        register FTSENTRY *tmp = p;
--
--        /* If we have so many directory entries that we're reading them
--           in batches, and we've reached the end of the current batch,
--           read in a new batch.  */
--        if (p->fts_link == NULL && FTSENT_DIRP(p->fts_parent))
--          {
--            p = tmp->fts_parent;
--            sp->fts_cur = p;
--            sp->fts_path[p->fts_pathlen] = '\0';
--
--            if ((p = fts_build (sp, BREAD)) == NULL)
--              {
--                if (ISSET(FTS_STOP))
--                  return NULL;
--                goto cd_dot_dot;
--              }
--
--            free(FTSENT_WRAPPER(tmp));
--            goto name;
--          }
--
--        if ((p = p->fts_link) != NULL) {
--                sp->fts_cur = p;
--                free(FTSENT_WRAPPER(tmp));
--
--                /*
--                 * If reached the top, return to the original directory (or
--                 * the root of the tree), and load the file names for the next
--                 * root.
--                 */
--                if (p->fts_level == FTS_ROOTLEVEL) {
--                        if (restore_initial_cwd(sp)) {
--                                SET(FTS_STOP);
--                                return (NULL);
--                        }
--                        free_dir(sp);
--                        fts_load(sp, p);
--                        if (! setup_dir(sp)) {
--                                free_dir(sp);
--                                return (NULL);
--                        }
--                        goto check_for_dir;
--                }
--
--                /*
--                 * User may have called fts_set on the node.  If skipped,
--                 * ignore.  If followed, get a file descriptor so we can
--                 * get back if necessary.
--                 */
--                if (p->fts_instr == FTS_SKIP)
--                        goto next;
--                if (p->fts_instr == FTS_FOLLOW) {
--                        p->fts_info = fts_stat(sp, p, true);
--                        if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
--                                if ((p->fts_symfd = diropen (sp, ".")) < 0) {
--                                        p->fts_errno = errno;
--                                        p->fts_info = FTS_ERR;
--                                } else
--                                        p->fts_flags |= FTS_SYMFOLLOW;
--                        }
--                        p->fts_instr = FTS_NOINSTR;
--                }
--
--name:           {
--                  register char *t = sp->fts_path + NAPPEND(p->fts_parent);
--                  *t++ = '/';
--                  memmove(t, p->fts_name, p->fts_namelen + 1);
--                }
--check_for_dir:
--                sp->fts_cur = p;
--                if (p->fts_info == FTS_NSOK)
--                  {
--                    if (p->fts_statp->st_size == FTS_STAT_REQUIRED)
--                      p->fts_info = fts_stat(sp, p, false);
--                    else
--                      fts_assert (p->fts_statp->st_size == FTS_NO_STAT_REQUIRED);
--                  }
--
--                /* Skip files with different device numbers when FTS_MOUNT
--                   is set.  */
--                if (ISSET (FTS_MOUNT) && p->fts_info != FTS_NS &&
--                    p->fts_level != FTS_ROOTLEVEL &&
--                    p->fts_statp->st_dev != sp->fts_dev)
--                      goto next;
--
--                if (p->fts_info == FTS_D)
--                  {
--                    /* Now that P->fts_statp is guaranteed to be valid, if
--                       this is a command-line directory, record its device
--                       number, to be used for FTS_MOUNT and FTS_XDEV.  */
--                    if (p->fts_level == FTS_ROOTLEVEL)
--                      sp->fts_dev = p->fts_statp->st_dev;
--                    Dprintf (("  entering: %s\n", p->fts_path));
--                    if (! enter_dir (sp, p))
--                      return NULL;
--                  }
--                return p;
--        }
--cd_dot_dot:
--
--        /* Move up to the parent node. */
--        p = tmp->fts_parent;
--        sp->fts_cur = p;
--        free(FTSENT_WRAPPER(tmp));
--
--        if (p->fts_level == FTS_ROOTPARENTLEVEL) {
--                /*
--                 * Done; free everything up and set errno to 0 so the user
--                 * can distinguish between error and EOF.
--                 */
--                free(FTSENT_WRAPPER(p));
--                __set_errno (0);
--                return (sp->fts_cur = NULL);
--        }
--
--        fts_assert (p->fts_info != FTS_NSOK);
--
--        /* NUL terminate the file name.  */
--        sp->fts_path[p->fts_pathlen] = '\0';
--
--        /*
--         * Return to the parent directory.  If at a root node, restore
--         * the initial working directory.  If we came through a symlink,
--         * go back through the file descriptor.  Otherwise, move up
--         * one level, via "..".
--         */
--        if (p->fts_level == FTS_ROOTLEVEL) {
--                if (restore_initial_cwd(sp)) {
--                        p->fts_errno = errno;
--                        SET(FTS_STOP);
--                }
--        } else if (p->fts_flags & FTS_SYMFOLLOW) {
--                if (FCHDIR(sp, p->fts_symfd)) {
--                        p->fts_errno = errno;
--                        SET(FTS_STOP);
--                }
--                (void)close(p->fts_symfd);
--        } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
--                   fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
--                p->fts_errno = errno;
--                SET(FTS_STOP);
--        }
--
--        /* If the directory causes a cycle, preserve the FTS_DC flag and keep
--           the corresponding dev/ino pair in the hash table.  It is going to be
--           removed when leaving the original directory.  */
--        if (p->fts_info != FTS_DC) {
--                p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
--                if (p->fts_errno == 0)
--                        LEAVE_DIR (sp, p, "3");
--        }
--        return ISSET(FTS_STOP) ? NULL : p;
-+	/*
-+	 * Following a symlink -- SLNONE test allows application to see
-+	 * SLNONE and recover.  If indirecting through a symlink, have
-+	 * keep a pointer to current location.  If unable to get that
-+	 * pointer, follow fails.
-+	 */
-+	if (instr == FTS_FOLLOW &&
-+	    (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
-+		p->fts_info = fts_stat(sp, p, 1);
-+		if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
-+			if ((p->fts_symfd = __open(".", O_RDONLY, 0)) < 0) {
-+				p->fts_errno = errno;
-+				p->fts_info = FTS_ERR;
-+			} else
-+				p->fts_flags |= FTS_SYMFOLLOW;
-+		}
-+		return (p);
-+	}
-+
-+	/* Directory in pre-order. */
-+	if (p->fts_info == FTS_D) {
-+		/* If skipped or crossed mount point, do post-order visit. */
-+		if (instr == FTS_SKIP ||
-+		    (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
-+			if (p->fts_flags & FTS_SYMFOLLOW)
-+				(void)__close(p->fts_symfd);
-+			if (sp->fts_child) {
-+				fts_lfree(sp->fts_child);
-+				sp->fts_child = NULL;
-+			}
-+			p->fts_info = FTS_DP;
-+			return (p);
-+		}
-+
-+		/* Rebuild if only read the names and now traversing. */
-+		if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
-+			CLR(FTS_NAMEONLY);
-+			fts_lfree(sp->fts_child);
-+			sp->fts_child = NULL;
-+		}
-+
-+		/*
-+		 * Cd to the subdirectory.
-+		 *
-+		 * If have already read and now fail to chdir, whack the list
-+		 * to make the names come out right, and set the parent errno
-+		 * so the application will eventually get an error condition.
-+		 * Set the FTS_DONTCHDIR flag so that when we logically change
-+		 * directories back to the parent we don't do a chdir.
-+		 *
-+		 * If haven't read do so.  If the read fails, fts_build sets
-+		 * FTS_STOP or the fts_info field of the node.
-+		 */
-+		if (sp->fts_child != NULL) {
-+			if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
-+				p->fts_errno = errno;
-+				p->fts_flags |= FTS_DONTCHDIR;
-+				for (p = sp->fts_child; p != NULL;
-+				     p = p->fts_link)
-+					p->fts_accpath =
-+					    p->fts_parent->fts_accpath;
-+			}
-+		} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
-+			if (ISSET(FTS_STOP))
-+				return (NULL);
-+			return (p);
-+		}
-+		p = sp->fts_child;
-+		sp->fts_child = NULL;
-+		sp->fts_cur = p;
-+		goto name;
-+	}
-+
-+	/* Move to the next node on this level. */
-+next:	tmp = p;
-+	if ((p = p->fts_link) != NULL) {
-+		sp->fts_cur = p;
-+		free(tmp);
-+
-+		/*
-+		 * If reached the top, return to the original directory (or
-+		 * the root of the tree), and load the paths for the next root.
-+		 */
-+		if (p->fts_level == FTS_ROOTLEVEL) {
-+			if (FCHDIR(sp, sp->fts_rfd)) {
-+				SET(FTS_STOP);
-+				return (NULL);
-+			}
-+			fts_load(sp, p);
-+			return p;
-+		}
-+
-+		/*
-+		 * User may have called fts_set on the node.  If skipped,
-+		 * ignore.  If followed, get a file descriptor so we can
-+		 * get back if necessary.
-+		 */
-+		if (p->fts_instr == FTS_SKIP)
-+			goto next;
-+		if (p->fts_instr == FTS_FOLLOW) {
-+			p->fts_info = fts_stat(sp, p, 1);
-+			if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
-+				if ((p->fts_symfd =
-+				    __open(".", O_RDONLY, 0)) < 0) {
-+					p->fts_errno = errno;
-+					p->fts_info = FTS_ERR;
-+				} else
-+					p->fts_flags |= FTS_SYMFOLLOW;
-+			}
-+			p->fts_instr = FTS_NOINSTR;
-+		}
-+
-+name:		t = sp->fts_path + NAPPEND(p->fts_parent);
-+		*t++ = '/';
-+		memmove(t, p->fts_name, p->fts_namelen + 1);
-+		return p;
-+	}
-+
-+	/* Move up to the parent node. */
-+	p = tmp->fts_parent;
-+	sp->fts_cur = p;
-+	free(tmp);
-+
-+	if (p->fts_level == FTS_ROOTPARENTLEVEL) {
-+		/*
-+		 * Done; free everything up and set errno to 0 so the user
-+		 * can distinguish between error and EOF.
-+		 */
-+		free(p);
-+		__set_errno (0);
-+		return (sp->fts_cur = NULL);
-+	}
-+
-+	/* NUL terminate the pathname. */
-+	sp->fts_path[p->fts_pathlen] = '\0';
-+
-+	/*
-+	 * Return to the parent directory.  If at a root node or came through
-+	 * a symlink, go back through the file descriptor.  Otherwise, cd up
-+	 * one directory.
-+	 */
-+	if (p->fts_level == FTS_ROOTLEVEL) {
-+		if (FCHDIR(sp, sp->fts_rfd)) {
-+			SET(FTS_STOP);
-+			return (NULL);
-+		}
-+	} else if (p->fts_flags & FTS_SYMFOLLOW) {
-+		if (FCHDIR(sp, p->fts_symfd)) {
-+			saved_errno = errno;
-+			(void)__close(p->fts_symfd);
-+			__set_errno (saved_errno);
-+			SET(FTS_STOP);
-+			return (NULL);
-+		}
-+		(void)__close(p->fts_symfd);
-+	} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
-+		   fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
-+		SET(FTS_STOP);
-+		return (NULL);
-+	}
-+	p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
-+	return p;
- }
- 
- /*
-@@ -1170,157 +506,93 @@ cd_dot_dot:
-  */
- /* ARGSUSED */
- int
--FTS_SET (_GL_UNUSED FTSOBJ *sp, FTSENTRY *p, int instr)
-+FTS_SET (FTSOBJ *sp, FTSENTRY *p, int instr)
- {
--        if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
--            instr != FTS_NOINSTR && instr != FTS_SKIP) {
--                __set_errno (EINVAL);
--                return (1);
--        }
--        p->fts_instr = instr;
--        return (0);
-+	if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
-+	    instr != FTS_NOINSTR && instr != FTS_SKIP) {
-+		__set_errno (EINVAL);
-+		return (1);
-+	}
-+	p->fts_instr = instr;
-+	return (0);
- }
- 
- FTSENTRY *
--FTS_CHILDREN (FTSOBJ *sp, int instr)
-+FTS_CHILDREN(FTSOBJ *sp, int instr)
- {
--        if (instr != 0 && instr != FTS_NAMEONLY) {
--                __set_errno (EINVAL);
--                return (NULL);
--        }
--
--        /* Set current node pointer. */
--        register FTSENTRY *p = sp->fts_cur;
--
--        /*
--         * Errno set to 0 so user can distinguish empty directory from
--         * an error.
--         */
--        __set_errno (0);
--
--        /* Fatal errors stop here. */
--        if (ISSET(FTS_STOP))
--                return (NULL);
--
--        /* Return logical hierarchy of user's arguments. */
--        if (p->fts_info == FTS_INIT)
--                return (p->fts_link);
--
--        /*
--         * If not a directory being visited in pre-order, stop here.  Could
--         * allow FTS_DNR, assuming the user has fixed the problem, but the
--         * same effect is available with FTS_AGAIN.
--         */
--        if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
--                return (NULL);
--
--        /* Free up any previous child list. */
--        if (sp->fts_child != NULL)
--                fts_lfree(sp->fts_child);
--
--        if (instr == FTS_NAMEONLY) {
--                SET(FTS_NAMEONLY);
--                instr = BNAMES;
--        } else
--                instr = BCHILD;
--
--        /*
--         * If using chdir on a relative file name and called BEFORE fts_read
--         * does its chdir to the root of a traversal, we can lose -- we need to
--         * chdir into the subdirectory, and we don't know where the current
--         * directory is, so we can't get back so that the upcoming chdir by
--         * fts_read will work.
--         */
--        if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
--            ISSET(FTS_NOCHDIR))
--                return (sp->fts_child = fts_build(sp, instr));
--
--        int fd = diropen (sp, ".");
--        if (fd < 0)
--                return (sp->fts_child = NULL);
--        sp->fts_child = fts_build(sp, instr);
--        if (ISSET(FTS_CWDFD))
--          {
--            cwd_advance_fd (sp, fd, true);
--          }
--        else
--          {
--            if (fchdir(fd))
--              {
--                int saved_errno = errno;
--                close (fd);
--                __set_errno (saved_errno);
--                return NULL;
--              }
--            close (fd);
--          }
--        return (sp->fts_child);
--}
-+	FTSENTRY *p;
-+	int fd;
- 
--/* A comparison function to sort on increasing inode number.
--   For some file system types, sorting either way makes a huge
--   performance difference for a directory with very many entries,
--   but sorting on increasing values is slightly better than sorting
--   on decreasing values.  The difference is in the 5% range.  */
--static int
--fts_compare_ino (FTSENTRY const **a, FTSENTRY const **b)
--{
--  return _GL_CMP (a[0]->fts_statp->st_ino, b[0]->fts_statp->st_ino);
-+	if (instr != 0 && instr != FTS_NAMEONLY) {
-+		__set_errno (EINVAL);
-+		return (NULL);
-+	}
-+
-+	/* Set current node pointer. */
-+	p = sp->fts_cur;
-+
-+	/*
-+	 * Errno set to 0 so user can distinguish empty directory from
-+	 * an error.
-+	 */
-+	__set_errno (0);
-+
-+	/* Fatal errors stop here. */
-+	if (ISSET(FTS_STOP))
-+		return (NULL);
-+
-+	/* Return logical hierarchy of user's arguments. */
-+	if (p->fts_info == FTS_INIT)
-+		return (p->fts_link);
-+
-+	/*
-+	 * If not a directory being visited in pre-order, stop here.  Could
-+	 * allow FTS_DNR, assuming the user has fixed the problem, but the
-+	 * same effect is available with FTS_AGAIN.
-+	 */
-+	if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
-+		return (NULL);
-+
-+	/* Free up any previous child list. */
-+	if (sp->fts_child != NULL)
-+		fts_lfree(sp->fts_child);
-+
-+	if (instr == FTS_NAMEONLY) {
-+		SET(FTS_NAMEONLY);
-+		instr = BNAMES;
-+	} else
-+		instr = BCHILD;
-+
-+	/*
-+	 * If using chdir on a relative path and called BEFORE fts_read does
-+	 * its chdir to the root of a traversal, we can lose -- we need to
-+	 * chdir into the subdirectory, and we don't know where the current
-+	 * directory is, so we can't get back so that the upcoming chdir by
-+	 * fts_read will work.
-+	 */
-+	if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
-+	    ISSET(FTS_NOCHDIR))
-+		return (sp->fts_child = fts_build(sp, instr));
-+
-+	if ((fd = __open(".", O_RDONLY, 0)) < 0)
-+		return (NULL);
-+	sp->fts_child = fts_build(sp, instr);
-+	if (__fchdir(fd))
-+		return (NULL);
-+	(void)__close(fd);
-+	return (sp->fts_child);
- }
- 
--/* Map the dirent.d_type value, DTYPE, to the corresponding stat.st_mode
--   S_IF* bit and set ST.st_mode, thus clearing all other bits in that field.  */
--static void
--set_stat_type (struct STRUCT_STAT *st, unsigned int dtype)
-+static inline int
-+dirent_not_directory(const struct dirent *dp)
- {
--  mode_t type;
--  switch (dtype)
--    {
--    case DT_BLK:
--      type = S_IFBLK;
--      break;
--    case DT_CHR:
--      type = S_IFCHR;
--      break;
--    case DT_DIR:
--      type = S_IFDIR;
--      break;
--    case DT_FIFO:
--      type = S_IFIFO;
--      break;
--    case DT_LNK:
--      type = S_IFLNK;
--      break;
--    case DT_REG:
--      type = S_IFREG;
--      break;
--    case DT_SOCK:
--      type = S_IFSOCK;
--      break;
--    default:
--      type = 0;
--    }
--  st->st_mode = type;
-+#if defined DT_DIR && defined _DIRENT_HAVE_D_TYPE
-+        return dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN;
-+#else
-+        return 0;
-+#endif
- }
- 
--#define closedir_and_clear(dirp)                \
--  do                                            \
--    {                                           \
--      closedir (dirp);                          \
--      dirp = NULL;                              \
--    }                                           \
--  while (0)
--
--#define fts_opendir(file, Pdir_fd)                              \
--        OPENDIRAT((! ISSET(FTS_NOCHDIR) && ISSET(FTS_CWDFD)     \
--                   ? sp->fts_cwd_fd : AT_FDCWD),                \
--                  file,                                         \
--                  (((ISSET(FTS_PHYSICAL)                        \
--                     && ! (ISSET(FTS_COMFOLLOW)                 \
--                           && cur->fts_level == FTS_ROOTLEVEL)) \
--                    ? O_NOFOLLOW : 0)),                         \
--                  Pdir_fd)
--
- /*
-  * This is the tricky part -- do not casually change *anything* in here.  The
-  * idea is to build the linked list of entries that are used by fts_children
-@@ -1336,873 +608,531 @@ set_stat_type (struct STRUCT_STAT *st, unsigned int dtype)
-  * been found, cutting the stat calls by about 2/3.
-  */
- static FTSENTRY *
--internal_function
--fts_build (register FTSOBJ *sp, int type)
-+fts_build (FTSOBJ *sp, int type)
- {
--        FTSENTRY *cur = sp->fts_cur;
--        bool continue_readdir = !!FTSENT_DIRP(cur);
--
--        /* When cur->fts_dirp is non-NULL, that means we should
--           continue calling readdir on that existing DIR* pointer
--           rather than opening a new one.  */
--        int dir_fd;
--        if (continue_readdir)
--          {
--            DIR *dp = FTSENT_DIRP(cur);
--            dir_fd = dirfd (dp);
--            if (dir_fd < 0)
--              {
--                int dirfd_errno = errno;
--                closedir_and_clear (FTSENT_DIRP(cur));
--                if (type == BREAD)
--                  {
--                    cur->fts_info = FTS_DNR;
--                    cur->fts_errno = dirfd_errno;
--                  }
--                return NULL;
--              }
--          }
--        else
--          {
--            /* Open the directory for reading.  If this fails, we're done.
--               If being called from fts_read, set the fts_info field. */
--            if ((FTSENT_DIRP (cur) = fts_opendir(cur->fts_accpath, &dir_fd)) == NULL)
--              {
--                if (type == BREAD)
--                  {
--                    cur->fts_info = FTS_DNR;
--                    cur->fts_errno = errno;
--                  }
--                return NULL;
--              }
--            /* Rather than calling fts_stat for each and every entry encountered
--               in the readdir loop (below), stat each directory only right after
--               opening it.  */
--            bool stat_optimization = cur->fts_info == FTS_NSOK;
--
--            if (stat_optimization
--                /* Also read the stat info again after opening a directory to
--                   reveal eventual changes caused by a submount triggered by
--                   the traversal.  But do it only for utilities which use
--                   FTS_TIGHT_CYCLE_CHECK.  Therefore, only find and du
--                   benefit/suffer from this feature for now.  */
--                || ISSET (FTS_TIGHT_CYCLE_CHECK))
--              {
--                if (!stat_optimization)
--                  LEAVE_DIR (sp, cur, "4");
--                if (FSTAT (dir_fd, cur->fts_statp) != 0)
--                  {
--                    int fstat_errno = errno;
--                    closedir_and_clear (FTSENT_DIRP(cur));
--                    if (type == BREAD)
--                      {
--                        cur->fts_errno = fstat_errno;
--                        cur->fts_info = FTS_NS;
--                      }
--                    __set_errno (fstat_errno);
--                    return NULL;
--                  }
--                if (stat_optimization)
--                  cur->fts_info = FTS_D;
--                else if (! enter_dir (sp, cur))
--                  {
--                    int saved_errno = errno;
--                    closedir_and_clear (FTSENT_DIRP(cur));
--                    __set_errno (saved_errno);
--                    return NULL;
--                  }
--              }
--          }
--
--        /* Maximum number of readdir entries to read at one time.  This
--           limitation is to avoid reading millions of entries into memory
--           at once.  When an fts_compar function is specified, we have no
--           choice: we must read all entries into memory before calling that
--           function.  But when no such function is specified, we can read
--           entries in batches that are large enough to help us with inode-
--           sorting, yet not so large that we risk exhausting memory.  */
--        size_t max_entries = sp->fts_compar ? SIZE_MAX : FTS_MAX_READDIR_ENTRIES;
--
--        /*
--         * If we're going to need to stat anything or we want to descend
--         * and stay in the directory, chdir.  If this fails we keep going,
--         * but set a flag so we don't chdir after the post-order visit.
--         * We won't be able to stat anything, but we can still return the
--         * names themselves.  Note, that since fts_read won't be able to
--         * chdir into the directory, it will have to return different file
--         * names than before, i.e. "a/b" instead of "b".  Since the node
--         * has already been visited in pre-order, have to wait until the
--         * post-order visit to return the error.  There is a special case
--         * here, if there was nothing to stat then it's not an error to
--         * not be able to stat.  This is all fairly nasty.  If a program
--         * needed sorted entries or stat information, they had better be
--         * checking FTS_NS on the returned nodes.
--         */
--        bool descend;
--        if (continue_readdir)
--          {
--            /* When resuming a short readdir run, we already have
--               the required dirp and dir_fd.  */
--            descend = true;
--          }
--        else
--          {
--            /* Try to descend unless it is a names-only fts_children,
--               or the directory is known to lack subdirectories.  */
--            descend = (type != BNAMES
--                       && ! (ISSET (FTS_NOSTAT) && ISSET (FTS_PHYSICAL)
--                             && ! ISSET (FTS_SEEDOT)
--                             && cur->fts_statp->st_nlink == MIN_DIR_NLINK
--                             && (leaf_optimization (cur, dir_fd)
--                                 != NO_LEAF_OPTIMIZATION)));
--            if (descend || type == BREAD)
--              {
--                if (ISSET(FTS_CWDFD))
--                  dir_fd = fcntl (dir_fd, F_DUPFD_CLOEXEC, STDERR_FILENO + 1);
--                if (dir_fd < 0 || fts_safe_changedir(sp, cur, dir_fd, NULL)) {
--                        if (descend && type == BREAD)
--                                cur->fts_errno = errno;
--                        cur->fts_flags |= FTS_DONTCHDIR;
--                        descend = false;
--                        closedir_and_clear(FTSENT_DIRP(cur));
--                        if (ISSET(FTS_CWDFD) && 0 <= dir_fd)
--                                close (dir_fd);
--                        FTSENT_DIRP(cur) = NULL;
--                } else
--                        descend = true;
--              }
--          }
--
--        /*
--         * Figure out the max file name length that can be stored in the
--         * current buffer -- the inner loop allocates more space as necessary.
--         * We really wouldn't have to do the maxlen calculations here, we
--         * could do them in fts_read before returning the name, but it's a
--         * lot easier here since the length is part of the dirent structure.
--         *
--         * If not changing directories set a pointer so that can just append
--         * each new component into the file name.
--         */
--        size_t len = NAPPEND(cur);
--        char *cp;
--        if (ISSET(FTS_NOCHDIR)) {
--                cp = sp->fts_path + len;
--                *cp++ = '/';
--        } else {
--                /* GCC, you're too verbose. */
--                cp = NULL;
--        }
--        len++;
--        size_t maxlen = sp->fts_pathlen - len;
--
--        ptrdiff_t level = cur->fts_level + 1;
--
--        /* Read the directory, attaching each entry to the "link" pointer. */
--        bool doadjust = false;
--        register FTSENTRY *head = NULL;
--        FTSENTRY *tail = NULL;
--        register size_t nitems = 0;
--        bool sort_by_inode = false;
--        while (FTSENT_DIRP(cur)) {
--                __set_errno (0);
--                struct dirent *dp = readdir(FTSENT_DIRP(cur));
--                if (dp == NULL) {
--                        /* Some readdir()s do not absorb ENOENT (dir
--                           deleted but open).  This bug was fixed in
--                           glibc 2.3 (2002).  */
--#if ! (2 < __GLIBC__ + (3 <= __GLIBC_MINOR__))
--                        if (errno == ENOENT)
--                          errno = 0;
-+	struct dirent *dp;
-+	FTSENTRY *p, *head;
-+	int nitems;
-+	FTSENTRY *cur, *tail;
-+	DIR *dirp;
-+	void *oldaddr;
-+	int cderrno, descend, len, level, nlinks, saved_errno,
-+	    nostat, doadjust;
-+	size_t maxlen;
-+	char *cp;
-+
-+	/* Set current node pointer. */
-+	cur = sp->fts_cur;
-+
-+	/*
-+	 * Open the directory for reading.  If this fails, we're done.
-+	 * If being called from fts_read, set the fts_info field.
-+	 */
-+#if defined FTS_WHITEOUT && 0
-+	if (ISSET(FTS_WHITEOUT))
-+		oflag = DTF_NODUP|DTF_REWIND;
-+	else
-+		oflag = DTF_HIDEW|DTF_NODUP|DTF_REWIND;
-+#else
-+# define __opendir2(path, flag) __opendir(path)
- #endif
--                        if (errno) {
--                                cur->fts_errno = errno;
--                                /* If we've not read any items yet, treat
--                                   the error as if we can't access the dir.  */
--                                cur->fts_info = (continue_readdir || nitems)
--                                                ? FTS_ERR : FTS_DNR;
--                        }
--                        closedir_and_clear(FTSENT_DIRP(cur));
--                        break;
--                }
--                if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
--                        continue;
--
--                size_t d_namelen = _D_EXACT_NAMLEN (dp);
--                register FTSENTRY *p = fts_alloc (sp, dp->d_name, d_namelen);
--                if (!p)
--                        goto mem1;
--                if (d_namelen >= maxlen) {
--                        /* include space for NUL */
--                        uintptr_t oldaddr = (uintptr_t) sp->fts_path;
--                        if (! fts_palloc(sp, d_namelen + len + 1)) {
--                                /*
--                                 * No more memory.  Save
--                                 * errno, free up the current structure and the
--                                 * structures already allocated.
--                                 */
--mem1: ;
--                                int saved_errno = errno;
--                                free(FTSENT_WRAPPER(p));
--                                fts_lfree(head);
--                                closedir_and_clear(FTSENT_DIRP(cur));
--                                cur->fts_info = FTS_ERR;
--                                SET(FTS_STOP);
--                                __set_errno (saved_errno);
--                                return (NULL);
--                        }
--                        /* Did realloc() change the pointer? */
--                        if (oldaddr != (uintptr_t) sp->fts_path) {
--                                doadjust = true;
--                                if (ISSET(FTS_NOCHDIR))
--                                        cp = sp->fts_path + len;
--                        }
--                        maxlen = sp->fts_pathlen - len;
--                }
--
--                size_t new_len = len + d_namelen;
--                if (new_len < len) {
--                        /*
--                         * In the unlikely event that we would end up
--                         * with a file name longer than SIZE_MAX, free up
--                         * the current structure and the structures already
--                         * allocated, then error out with ENAMETOOLONG.
--                         */
--                        free(FTSENT_WRAPPER(p));
--                        fts_lfree(head);
--                        closedir_and_clear(FTSENT_DIRP(cur));
--                        cur->fts_info = FTS_ERR;
--                        SET(FTS_STOP);
--                        __set_errno (ENAMETOOLONG);
--                        return (NULL);
--                }
--                p->fts_level = level;
--                p->fts_parent = sp->fts_cur;
--                p->fts_pathlen = new_len;
--
--                /* Store dirent.d_ino, in case we need to sort
--                   entries before processing them.  */
--                p->fts_statp->st_ino = D_INO (dp);
--
--                /* Build a file name for fts_stat to stat. */
--                if (ISSET(FTS_NOCHDIR)) {
--                        p->fts_accpath = p->fts_path;
--                        memmove(cp, p->fts_name, p->fts_namelen + 1);
--                } else
--                        p->fts_accpath = p->fts_name;
--
--                if (sp->fts_compar == NULL || ISSET(FTS_DEFER_STAT)) {
--                        /* Record what fts_read will have to do with this
--                           entry. In many cases, it will simply fts_stat it,
--                           but we can take advantage of any d_type information
--                           to optimize away the unnecessary stat calls.  I.e.,
--                           if FTS_NOSTAT is in effect, we don't need device
--                           numbers unconditionally (FTS_MOUNT) and we're not
--                           following symlinks (FTS_PHYSICAL) and d_type
--                           indicates this is *not* a directory, then we won't
--                           have to stat it  at all.  If it *is* a directory,
--                           then (currently) we stat it regardless, in order to
--                           get device and inode numbers.  Some day we might
--                           optimize that away, too, for directories where
--                           d_ino is known to be valid.  */
--                        bool skip_stat = (ISSET(FTS_NOSTAT)
--                                          && DT_IS_KNOWN(dp)
--                                          && ! DT_MUST_BE(dp, DT_DIR)
--                                          && (ISSET(FTS_PHYSICAL)
--                                              || ! DT_MUST_BE(dp, DT_LNK))
--                                          && ! ISSET(FTS_MOUNT));
--                        p->fts_info = FTS_NSOK;
--                        /* Propagate dirent.d_type information back
--                           to caller, when possible.  */
--                        set_stat_type (p->fts_statp, D_TYPE (dp));
--                        fts_set_stat_required(p, !skip_stat);
--                } else {
--                        p->fts_info = fts_stat(sp, p, false);
--                }
--
--                /* We walk in directory order so "ls -f" doesn't get upset. */
--                p->fts_link = NULL;
--                if (head == NULL)
--                        head = tail = p;
--                else {
--                        tail->fts_link = p;
--                        tail = p;
--                }
--
--                /* If there are many entries, no sorting function has been
--                   specified, and this file system is of a type that may be
--                   slow with a large number of entries, arrange to sort the
--                   directory entries on increasing inode numbers.
--
--                   The NITEMS comparison uses ==, not >, because the test
--                   needs to be tried at most once once, and NITEMS will exceed
--                   the threshold after it is incremented below.  */
--                if (nitems == _FTS_INODE_SORT_DIR_ENTRIES_THRESHOLD
--                    && !sp->fts_compar)
--                  sort_by_inode = dirent_inode_sort_may_be_useful (cur, dir_fd);
--
--                ++nitems;
--                if (max_entries <= nitems) {
--                        /* When there are too many dir entries, leave
--                           fts_dirp open, so that a subsequent fts_read
--                           can take up where we leave off.  */
--                        break;
--                }
--        }
--
--        /*
--         * If realloc() changed the address of the file name, adjust the
--         * addresses for the rest of the tree and the dir list.
--         */
--        if (doadjust)
--                fts_padjust(sp, head);
--
--        /*
--         * If not changing directories, reset the file name back to original
--         * state.
--         */
--        if (ISSET(FTS_NOCHDIR)) {
--                if (len == sp->fts_pathlen || nitems == 0)
--                        --cp;
--                *cp = '\0';
--        }
--
--        /*
--         * If descended after called from fts_children or after called from
--         * fts_read and nothing found, get back.  At the root level we use
--         * the saved fd; if one of fts_open()'s arguments is a relative name
--         * to an empty directory, we wind up here with no other way back.  If
--         * can't get back, we're done.
--         */
--        if (!continue_readdir && descend && (type == BCHILD || !nitems) &&
--            (cur->fts_level == FTS_ROOTLEVEL
--             ? restore_initial_cwd(sp)
--             : fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
--                cur->fts_info = FTS_ERR;
--                SET(FTS_STOP);
--                fts_lfree(head);
--                return (NULL);
--        }
--
--        /* If didn't find anything, return NULL. */
--        if (!nitems) {
--                if (type == BREAD
--                    && cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR)
--                        cur->fts_info = FTS_DP;
--                fts_lfree(head);
--                return (NULL);
--        }
--
--        if (sort_by_inode) {
--                sp->fts_compar = FTS_COMPAR_CAST (fts_compare_ino);
--                head = fts_sort (sp, head, nitems);
--                sp->fts_compar = NULL;
--        }
--
--        /* Sort the entries. */
--        if (sp->fts_compar && nitems > 1)
--                head = fts_sort(sp, head, nitems);
--        return (head);
--}
-+       if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
-+		if (type == BREAD) {
-+			cur->fts_info = FTS_DNR;
-+			cur->fts_errno = errno;
-+		}
-+		return (NULL);
-+	}
- 
--#if GNULIB_FTS_DEBUG
-+	/*
-+	 * Nlinks is the number of possible entries of type directory in the
-+	 * directory if we're cheating on stat calls, 0 if we're not doing
-+	 * any stat calls at all, -1 if we're doing stats on everything.
-+	 */
-+	if (type == BNAMES) {
-+		nlinks = 0;
-+		/* Be quiet about nostat, GCC. */
-+		nostat = 0;
-+	} else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
-+		nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
-+		nostat = 1;
-+	} else {
-+		nlinks = -1;
-+		nostat = 0;
-+	}
-+
-+#ifdef notdef
-+	(void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
-+	(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
-+	    ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
-+#endif
-+	/*
-+	 * If we're going to need to stat anything or we want to descend
-+	 * and stay in the directory, chdir.  If this fails we keep going,
-+	 * but set a flag so we don't chdir after the post-order visit.
-+	 * We won't be able to stat anything, but we can still return the
-+	 * names themselves.  Note, that since fts_read won't be able to
-+	 * chdir into the directory, it will have to return different path
-+	 * names than before, i.e. "a/b" instead of "b".  Since the node
-+	 * has already been visited in pre-order, have to wait until the
-+	 * post-order visit to return the error.  There is a special case
-+	 * here, if there was nothing to stat then it's not an error to
-+	 * not be able to stat.  This is all fairly nasty.  If a program
-+	 * needed sorted entries or stat information, they had better be
-+	 * checking FTS_NS on the returned nodes.
-+	 */
-+	cderrno = 0;
-+	if (nlinks || type == BREAD) {
-+		if (fts_safe_changedir(sp, cur, dirfd(dirp), NULL)) {
-+			if (nlinks && type == BREAD)
-+				cur->fts_errno = errno;
-+			cur->fts_flags |= FTS_DONTCHDIR;
-+			descend = 0;
-+			cderrno = errno;
-+			(void)__closedir(dirp);
-+			dirp = NULL;
-+		} else
-+			descend = 1;
-+	} else
-+		descend = 0;
- 
--struct devino {
--  intmax_t dev, ino;
--};
--#define PRINT_DEVINO "(%jd,%jd)"
-+	/*
-+	 * Figure out the max file name length that can be stored in the
-+	 * current path -- the inner loop allocates more path as necessary.
-+	 * We really wouldn't have to do the maxlen calculations here, we
-+	 * could do them in fts_read before returning the path, but it's a
-+	 * lot easier here since the length is part of the dirent structure.
-+	 *
-+	 * If not changing directories set a pointer so that can just append
-+	 * each new name into the path.
-+	 */
-+	len = NAPPEND(cur);
-+	if (ISSET(FTS_NOCHDIR)) {
-+		cp = sp->fts_path + len;
-+		*cp++ = '/';
-+	} else {
-+		/* GCC, you're too verbose. */
-+		cp = NULL;
-+	}
-+	len++;
-+	maxlen = sp->fts_pathlen - len;
-+
-+	level = cur->fts_level + 1;
-+
-+	/* Read the directory, attaching each entry to the `link' pointer. */
-+	doadjust = 0;
-+	for (head = tail = NULL, nitems = 0; dirp && (dp = __readdir(dirp));) {
-+		if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
-+			continue;
-+
-+		if ((p = fts_alloc(sp, dp->d_name, _D_EXACT_NAMLEN (dp))) == NULL)
-+			goto mem1;
-+		if (_D_EXACT_NAMLEN (dp) >= maxlen) {/* include space for NUL */
-+			oldaddr = sp->fts_path;
-+			if (fts_palloc(sp, _D_EXACT_NAMLEN (dp) + len + 1)) {
-+				/*
-+				 * No more memory for path or structures.  Save
-+				 * errno, free up the current structure and the
-+				 * structures already allocated.
-+				 */
-+mem1:				saved_errno = errno;
-+				free(p);
-+				fts_lfree(head);
-+				(void)__closedir(dirp);
-+				cur->fts_info = FTS_ERR;
-+				SET(FTS_STOP);
-+				__set_errno (saved_errno);
-+				return (NULL);
-+			}
-+			/* Did realloc() change the pointer? */
-+			if (oldaddr != sp->fts_path) {
-+				doadjust = 1;
-+				if (ISSET(FTS_NOCHDIR))
-+					cp = sp->fts_path + len;
-+			}
-+			maxlen = sp->fts_pathlen - len;
-+		}
-+
-+		if (len + _D_EXACT_NAMLEN (dp) >= USHRT_MAX) {
-+			/*
-+			 * In an FTSENT, fts_pathlen is a u_short so it is
-+			 * possible to wraparound here.  If we do, free up
-+			 * the current structure and the structures already
-+			 * allocated, then error out with ENAMETOOLONG.
-+			 */
-+			free(p);
-+			fts_lfree(head);
-+			(void)__closedir(dirp);
-+			cur->fts_info = FTS_ERR;
-+			SET(FTS_STOP);
-+			__set_errno (ENAMETOOLONG);
-+			return (NULL);
-+		}
-+		p->fts_level = level;
-+		p->fts_parent = sp->fts_cur;
-+		p->fts_pathlen = len + _D_EXACT_NAMLEN (dp);
-+
-+#if defined FTS_WHITEOUT && 0
-+		if (dp->d_type == DT_WHT)
-+			p->fts_flags |= FTS_ISW;
-+#endif
- 
--static struct devino
--getdevino (int fd)
--{
--  struct STRUCT_STAT st;
--  return (fd == AT_FDCWD
--          ? (struct devino) { -1, 0 }
--          : FSTAT (fd, &st) == 0
--          ? (struct devino) { st.st_dev, st.st_ino }
--          : (struct devino) { -1, errno });
--}
-+		/* Unreachable code.  cderrno is only ever set to a nonnull
-+		   value if dirp is closed at the same time.  But then we
-+		   cannot enter this loop.  */
-+		if (0 && cderrno) {
-+			if (nlinks) {
-+				p->fts_info = FTS_NS;
-+				p->fts_errno = cderrno;
-+			} else
-+				p->fts_info = FTS_NSOK;
-+			p->fts_accpath = cur->fts_accpath;
-+		} else if (nlinks == 0
-+                           || (nostat && dirent_not_directory(dp))) {
-+			p->fts_accpath =
-+			    ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
-+			p->fts_info = FTS_NSOK;
-+		} else {
-+			/* Build a file name for fts_stat to stat. */
-+			if (ISSET(FTS_NOCHDIR)) {
-+				p->fts_accpath = p->fts_path;
-+				memmove(cp, p->fts_name, p->fts_namelen + 1);
-+			} else
-+				p->fts_accpath = p->fts_name;
-+			/* Stat it. */
-+			p->fts_info = fts_stat(sp, p, 0);
-+
-+			/* Decrement link count if applicable. */
-+			if (nlinks > 0 && (p->fts_info == FTS_D ||
-+			    p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
-+				--nlinks;
-+		}
-+
-+		/* We walk in directory order so "ls -f" doesn't get upset. */
-+		p->fts_link = NULL;
-+		if (head == NULL)
-+			head = tail = p;
-+		else {
-+			tail->fts_link = p;
-+			tail = p;
-+		}
-+		++nitems;
-+	}
-+	if (dirp)
-+		(void)__closedir(dirp);
- 
--/* Walk ->fts_parent links starting at E_CURR, until the root of the
--   current hierarchy.  There should be a directory with dev/inode
--   matching those of AD.  If not, print a lot of diagnostics.  */
--static void
--find_matching_ancestor (FTSENTRY const *e_curr, struct Active_dir const *ad)
--{
--  for (FTSENTRY const *ent = e_curr;
--       ent->fts_level >= FTS_ROOTLEVEL;
--       ent = ent->fts_parent)
--    {
--      if (ad->ino == ent->fts_statp->st_ino
--          && ad->dev == ent->fts_statp->st_dev)
--        return;
--    }
--  printf ("ERROR: tree dir, %s, not active\n", ad->fts_ent->fts_accpath);
--  printf ("active dirs:\n");
--  for (FTSENTRY const *ent = e_curr;
--       ent->fts_level >= FTS_ROOTLEVEL;
--       ent = ent->fts_parent)
--    printf ("  %s(%"PRIuMAX"/%"PRIuMAX") to %s(%"PRIuMAX"/%"PRIuMAX")...\n",
--            ad->fts_ent->fts_accpath,
--            (uintmax_t) ad->dev,
--            (uintmax_t) ad->ino,
--            ent->fts_accpath,
--            (uintmax_t) ent->fts_statp->st_dev,
--            (uintmax_t) ent->fts_statp->st_ino);
--}
-+	/*
-+	 * If realloc() changed the address of the path, adjust the
-+	 * addresses for the rest of the tree and the dir list.
-+	 */
-+	if (doadjust)
-+		fts_padjust(sp, head);
- 
--void
--fts_cross_check (FTSOBJ const *sp)
--{
--  if ( ! ISSET (FTS_TIGHT_CYCLE_CHECK))
--    return;
--
--  FTSENTRY const *ent = sp->fts_cur;
--
--  Dprintf (("fts-cross-check cur=%s\n", ent->fts_path));
--  /* Make sure every parent dir is in the tree.  */
--  for (FTSENTRY const *t = ent->fts_parent;
--       t->fts_level >= FTS_ROOTLEVEL;
--       t = t->fts_parent)
--    {
--      struct Active_dir ad;
--      ad.ino = t->fts_statp->st_ino;
--      ad.dev = t->fts_statp->st_dev;
--      if ( ! hash_lookup (sp->fts_cycle.ht, &ad))
--        printf ("ERROR: active dir, %s, not in tree\n", t->fts_path);
--    }
--
--  /* Make sure every dir in the tree is an active dir.
--     But ENT is not necessarily a directory.  If so, just skip this part. */
--  if (ent->fts_parent->fts_level >= FTS_ROOTLEVEL
--      && (ent->fts_info == FTS_DP
--          || ent->fts_info == FTS_D))
--    for (struct Active_dir *ad = hash_get_first (sp->fts_cycle.ht);
--         ad != NULL;
--         ad = hash_get_next (sp->fts_cycle.ht, ad))
--      {
--        find_matching_ancestor (ent, ad);
--      }
--}
-+	/*
-+	 * If not changing directories, reset the path back to original
-+	 * state.
-+	 */
-+	if (ISSET(FTS_NOCHDIR)) {
-+		if (len == sp->fts_pathlen || nitems == 0)
-+			--cp;
-+		*cp = '\0';
-+	}
- 
--static bool
--same_fd (int fd1, int fd2)
--{
--  struct STRUCT_STAT sb1, sb2;
--  return (FSTAT (fd1, &sb1) == 0
--          && FSTAT (fd2, &sb2) == 0
--          && psame_inode (&sb1, &sb2));
--}
-+	/*
-+	 * If descended after called from fts_children or after called from
-+	 * fts_read and nothing found, get back.  At the root level we use
-+	 * the saved fd; if one of fts_open()'s arguments is a relative path
-+	 * to an empty directory, we wind up here with no other way back.  If
-+	 * can't get back, we're done.
-+	 */
-+	if (descend && (type == BCHILD || !nitems) &&
-+	    (cur->fts_level == FTS_ROOTLEVEL ?
-+	     FCHDIR(sp, sp->fts_rfd) :
-+	     fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
-+		cur->fts_info = FTS_ERR;
-+		SET(FTS_STOP);
-+		fts_lfree(head);
-+		return (NULL);
-+	}
- 
--static void
--fd_ring_print (FTSOBJ const *sp, FILE *stream, char const *msg)
--{
--  if (!fts_debug)
--    return;
--  I_ring const *fd_ring = &sp->fts_fd_ring;
--  struct devino cwd = getdevino (sp->fts_cwd_fd);
--  fprintf (stream, "=== %s ========== "PRINT_DEVINO"\n", msg, cwd.dev, cwd.ino);
--  if (i_ring_empty (fd_ring))
--    return;
--
--  unsigned int i = fd_ring->ir_front;
--  while (true)
--    {
--      int fd = fd_ring->ir_data[i];
--      if (fd < 0)
--        fprintf (stream, "%u: %d:\n", i, fd);
--      else
--        {
--          struct devino wd = getdevino (fd);
--          fprintf (stream, "%u: %d: "PRINT_DEVINO"\n", i, fd, wd.dev, wd.ino);
--        }
--      if (i == fd_ring->ir_back)
--        break;
--      i = (i + I_RING_SIZE - 1) % I_RING_SIZE;
--    }
--}
-+	/* If didn't find anything, return NULL. */
-+	if (!nitems) {
-+		if (type == BREAD)
-+			cur->fts_info = FTS_DP;
-+		fts_lfree(head);
-+		return (NULL);
-+	}
- 
--/* Ensure that each file descriptor on the fd_ring matches a
--   parent, grandparent, etc. of the current working directory.  */
--static void
--fd_ring_check (FTSOBJ const *sp)
--{
--  if (!fts_debug)
--    return;
--
--  /* Make a writable copy.  */
--  I_ring fd_w = sp->fts_fd_ring;
--
--  int cwd_fd = sp->fts_cwd_fd;
--  cwd_fd = fcntl (cwd_fd, F_DUPFD_CLOEXEC, STDERR_FILENO + 1);
--  struct devino dot = getdevino (cwd_fd);
--  fprintf (stderr, "===== check ===== cwd: "PRINT_DEVINO"\n",
--           dot.dev, dot.ino);
--  while ( ! i_ring_empty (&fd_w))
--    {
--      int fd = i_ring_pop (&fd_w);
--      if (0 <= fd)
--        {
--          int open_flags = O_SEARCH | O_CLOEXEC;
--          int parent_fd = openat (cwd_fd, "..", open_flags);
--          if (parent_fd < 0)
--            {
--              // Warn?
--              break;
--            }
--          if (!same_fd (fd, parent_fd))
--            {
--              struct devino cwd = getdevino (fd);
--              fprintf (stderr, "ring  : "PRINT_DEVINO"\n", cwd.dev, cwd.ino);
--              struct devino c2 = getdevino (parent_fd);
--              fprintf (stderr, "parent: "PRINT_DEVINO"\n", c2.dev, c2.ino);
--              fts_assert (0);
--            }
--          close (cwd_fd);
--          cwd_fd = parent_fd;
--        }
--    }
--  close (cwd_fd);
-+	/* Sort the entries. */
-+	if (sp->fts_compar && nitems > 1)
-+		head = fts_sort(sp, head, nitems);
-+	return (head);
- }
--#endif
- 
--static unsigned short int
--internal_function
--fts_stat(FTSOBJ *sp, register FTSENTRY *p, bool follow)
-+static u_short
-+fts_stat (FTSOBJ *sp, FTSENTRY *p, int follow)
- {
--        if (ISSET (FTS_LOGICAL)
--            || (ISSET (FTS_COMFOLLOW) && p->fts_level == FTS_ROOTLEVEL))
--                follow = true;
--
--        struct STRUCT_STAT *sbp = p->fts_statp;
--
--        /*
--         * If doing a logical walk, or application requested FTS_FOLLOW, do
--         * a stat(2).  If that fails, check for a nonexistent symlink.  If
--         * fail, set the errno from the stat call.
--         */
--        int flags = follow ? 0 : AT_SYMLINK_NOFOLLOW;
--        if (FSTATAT (sp->fts_cwd_fd, p->fts_accpath, sbp, flags) < 0)
--          {
--            if (follow && errno == ENOENT
--                && 0 <= FSTATAT (sp->fts_cwd_fd, p->fts_accpath, sbp,
--                                 AT_SYMLINK_NOFOLLOW))
--              {
--                __set_errno (0);
--                return FTS_SLNONE;
--              }
--
--            p->fts_errno = errno;
--           memset (sbp, 0, sizeof *sbp);
--            return FTS_NS;
--          }
--
--        if (S_ISDIR(sbp->st_mode)) {
--                if (ISDOT(p->fts_name)) {
--                        /* Command-line "." and ".." are real directories. */
--                        return (p->fts_level == FTS_ROOTLEVEL ? FTS_D : FTS_DOT);
--                }
--
--                return (FTS_D);
--        }
--        if (S_ISLNK(sbp->st_mode))
--                return (FTS_SL);
--        if (S_ISREG(sbp->st_mode))
--                return (FTS_F);
--        return (FTS_DEFAULT);
--}
-+	FTSENTRY *t;
-+	dev_t dev;
-+	INO_T ino;
-+	struct STRUCT_STAT *sbp, sb;
-+	int saved_errno;
-+
-+	/* If user needs stat info, stat buffer already allocated. */
-+	sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
-+
-+#if defined FTS_WHITEOUT && 0
-+	/* check for whiteout */
-+	if (p->fts_flags & FTS_ISW) {
-+		if (sbp != &sb) {
-+			memset(sbp, '\0', sizeof (*sbp));
-+			sbp->st_mode = S_IFWHT;
-+		}
-+		return (FTS_W);
-+       }
-+#endif
- 
--static int
--fts_compar (void const *a, void const *b)
--{
--  /* Convert A and B to the correct types, to pacify the compiler, and
--     for portability to bizarre hosts where "void const *" and "FTSENT
--     const **" differ in runtime representation.  The comparison
--     function cannot modify *a and *b, but there is no compile-time
--     check for this.  */
--  FTSENTRY const **pa = (FTSENTRY const **) a;
--  FTSENTRY const **pb = (FTSENTRY const **) b;
--  return FTSENT_FTS(pa[0])->fts_compar (pa, pb);
-+	/*
-+	 * If doing a logical walk, or application requested FTS_FOLLOW, do
-+	 * a stat(2).  If that fails, check for a non-existent symlink.  If
-+	 * fail, set the errno from the stat call.
-+	 */
-+	if (ISSET(FTS_LOGICAL) || follow) {
-+		if (STAT(p->fts_accpath, sbp)) {
-+			saved_errno = errno;
-+			if (!LSTAT(p->fts_accpath, sbp)) {
-+				__set_errno (0);
-+				return (FTS_SLNONE);
-+			}
-+			p->fts_errno = saved_errno;
-+			goto err;
-+		}
-+	} else if (LSTAT(p->fts_accpath, sbp)) {
-+		p->fts_errno = errno;
-+err:		memset(sbp, 0, sizeof(struct STRUCT_STAT));
-+		return (FTS_NS);
-+	}
-+
-+	if (S_ISDIR(sbp->st_mode)) {
-+		/*
-+		 * Set the device/inode.  Used to find cycles and check for
-+		 * crossing mount points.  Also remember the link count, used
-+		 * in fts_build to limit the number of stat calls.  It is
-+		 * understood that these fields are only referenced if fts_info
-+		 * is set to FTS_D.
-+		 */
-+		dev = p->fts_dev = sbp->st_dev;
-+		ino = p->fts_ino = sbp->st_ino;
-+		p->fts_nlink = sbp->st_nlink;
-+
-+		if (ISDOT(p->fts_name))
-+			return (FTS_DOT);
-+
-+		/*
-+		 * Cycle detection is done by brute force when the directory
-+		 * is first encountered.  If the tree gets deep enough or the
-+		 * number of symbolic links to directories is high enough,
-+		 * something faster might be worthwhile.
-+		 */
-+		for (t = p->fts_parent;
-+		    t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
-+			if (ino == t->fts_ino && dev == t->fts_dev) {
-+				p->fts_cycle = t;
-+				return (FTS_DC);
-+			}
-+		return (FTS_D);
-+	}
-+	if (S_ISLNK(sbp->st_mode))
-+		return (FTS_SL);
-+	if (S_ISREG(sbp->st_mode))
-+		return (FTS_F);
-+	return (FTS_DEFAULT);
- }
- 
- static FTSENTRY *
--internal_function
--fts_sort (FTSOBJ *sp, FTSENTRY *head, register size_t nitems)
-+fts_sort (FTSOBJ *sp, FTSENTRY *head, int nitems)
- {
--        register FTSENTRY **ap, *p;
--
--        /* On most modern hosts, void * and FTSENT ** have the same
--           run-time representation, and one can convert sp->fts_compar to
--           the type qsort expects without problem.  Use the heuristic that
--           this is OK if the two pointer types are the same size, and if
--           converting FTSENT ** to uintptr_t is the same as converting
--           FTSENT ** to void * and then to uintptr_t.  This heuristic isn't
--           valid in general but we don't know of any counterexamples.  */
--        FTSENTRY *dummy;
--        int (*compare) (void const *, void const *) =
--          ((sizeof &dummy == sizeof (void *)
--            && (uintptr_t) &dummy == (uintptr_t) (void *) &dummy)
--           ? (int (*) (void const *, void const *)) sp->fts_compar
--           : fts_compar);
--
--        /*
--         * Construct an array of pointers to the structures and call qsort(3).
--         * Reassemble the array in the order returned by qsort.  If unable to
--         * sort for memory reasons, return the directory entries in their
--         * current order.  Allocate enough space for the current needs plus
--         * 40 so don't realloc one entry at a time.
--         */
--        if (nitems > sp->fts_nitems) {
--                sp->fts_nitems = nitems + 40;
--                FTSENTRY **a;
--                if (! (a = reallocarray (sp->fts_array,
--                                         sp->fts_nitems, sizeof *a))) {
--                        free(sp->fts_array);
--                        sp->fts_array = NULL;
--                        sp->fts_nitems = 0;
--                        return (head);
--                }
--                sp->fts_array = a;
--        }
--        for (ap = sp->fts_array, p = head; p; p = p->fts_link)
--                *ap++ = p;
--        qsort((void *)sp->fts_array, nitems, sizeof(FTSENTRY *), compare);
--        for (head = *(ap = sp->fts_array); --nitems; ++ap)
--                ap[0]->fts_link = ap[1];
--        ap[0]->fts_link = NULL;
--        return (head);
-+	FTSENTRY **ap, *p;
-+
-+	/*
-+	 * Construct an array of pointers to the structures and call qsort(3).
-+	 * Reassemble the array in the order returned by qsort.  If unable to
-+	 * sort for memory reasons, return the directory entries in their
-+	 * current order.  Allocate enough space for the current needs plus
-+	 * 40 so don't realloc one entry at a time.
-+	 */
-+	if (nitems > sp->fts_nitems) {
-+		FTSENTRY **a;
-+
-+		sp->fts_nitems = nitems + 40;
-+		if ((a = realloc(sp->fts_array,
-+		    (size_t)(sp->fts_nitems * sizeof(FTSENTRY *)))) == NULL) {
-+			free(sp->fts_array);
-+			sp->fts_array = NULL;
-+			sp->fts_nitems = 0;
-+			return (head);
-+		}
-+		sp->fts_array = a;
-+	}
-+	for (ap = sp->fts_array, p = head; p; p = p->fts_link)
-+		*ap++ = p;
-+	qsort((void *)sp->fts_array, nitems, sizeof(FTSENTRY *), sp->fts_compar);
-+	for (head = *(ap = sp->fts_array); --nitems; ++ap)
-+		ap[0]->fts_link = ap[1];
-+	ap[0]->fts_link = NULL;
-+	return (head);
- }
- 
- static FTSENTRY *
--internal_function
--fts_alloc (FTSOBJ *sp, const char *name, register size_t namelen)
-+fts_alloc (FTSOBJ *sp, const char *name, size_t namelen)
- {
--        /*
--         * The file name is a variable length array.  Allocate the FTSENT
--         * structure and the file name in one chunk.
--         */
--        size_t len = FLEXSIZEOF(FTSENT, fts_name, namelen + 1);
--	register FTSENTRY *p;
--#if !_LIBC
--        p = malloc(len);
--        if (p == NULL)
--                return (NULL);
--#else
-+	FTSENTRY *p;
-+	size_t len;
-+
- 	/*
--	 * For glibc, we use a wrapper struct to provide the extra required
--	 * fields without changing the FSENT layout.
-+	 * The file name is a variable length array and no stat structure is
-+	 * necessary if the user has set the nostat bit.  Allocate the FTSENT
-+	 * structure, the file name and the stat structure in one chunk, but
-+	 * be careful that the stat structure is reasonably aligned.  Since the
-+	 * fts_name field is declared to be of size 1, the fts_name pointer is
-+	 * namelen + 2 before the first possible address of the stat structure.
- 	 */
--	len += sizeof (struct FTSENT_wrapper);
--	struct FTSENT_wrapper *wrapper = malloc(len);
--	if (wrapper == NULL)
-+	len = sizeof(FTSENTRY) + namelen;
-+	if (!ISSET(FTS_NOSTAT))
-+		len += sizeof(struct STRUCT_STAT) + ALIGNBYTES;
-+	if ((p = malloc(len)) == NULL)
- 		return (NULL);
--	p = &wrapper->ent;
--        p->fts_statp = &wrapper->fts_stat;
--#endif
- 
--        /* Copy the name and guarantee NUL termination. */
--        memcpy(p->fts_name, name, namelen);
--        p->fts_name[namelen] = '\0';
--
--        p->fts_namelen = namelen;
--        FTSENT_FTS(p)= sp;
--        p->fts_path = sp->fts_path;
--        p->fts_errno = 0;
--        FTSENT_DIRP(p) = NULL;
--        p->fts_flags = 0;
--        p->fts_instr = FTS_NOINSTR;
--        p->fts_number = 0;
--        p->fts_pointer = NULL;
--        return (p);
-+	/* Copy the name and guarantee NUL termination. */
-+	memmove(p->fts_name, name, namelen);
-+	p->fts_name[namelen] = '\0';
-+
-+	if (!ISSET(FTS_NOSTAT))
-+		p->fts_statp = (struct STRUCT_STAT *)ALIGN(p->fts_name + namelen + 2);
-+	p->fts_namelen = namelen;
-+	p->fts_path = sp->fts_path;
-+	p->fts_errno = 0;
-+	p->fts_flags = 0;
-+	p->fts_instr = FTS_NOINSTR;
-+	p->fts_number = 0;
-+	p->fts_pointer = NULL;
-+	return (p);
- }
- 
- static void
--internal_function
--fts_lfree (register FTSENTRY *head)
-+fts_lfree (FTSENTRY *head)
- {
--        int saved_errno = errno;
--
--        /* Free a linked list of structures. */
--        register FTSENTRY *p;
--        while ((p = head)) {
--                head = head->fts_link;
--                if (FTSENT_DIRP(p))
--                        closedir (FTSENT_DIRP(p));
--                free(FTSENT_WRAPPER(p));
--        }
--
--        __set_errno (saved_errno);
-+	FTSENTRY *p;
-+
-+	/* Free a linked list of structures. */
-+	while ((p = head)) {
-+		head = head->fts_link;
-+		free(p);
-+	}
- }
- 
- /*
-- * Allow essentially unlimited file name lengths; find, rm, ls should
-- * all work on any tree.  Most systems will allow creation of file
-- * names much longer than MAXPATHLEN, even though the kernel won't
-- * resolve them.  Add the size (not just what's needed) plus 256 bytes
-- * so don't realloc the file name 2 bytes at a time.
-+ * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
-+ * Most systems will allow creation of paths much longer than MAXPATHLEN, even
-+ * though the kernel won't resolve them.  Add the size (not just what's needed)
-+ * plus 256 bytes so don't realloc the path 2 bytes at a time.
-  */
--static bool
--internal_function
-+static int
- fts_palloc (FTSOBJ *sp, size_t more)
- {
--        size_t new_len = sp->fts_pathlen + more + 256;
--
--        /*
--         * See if fts_pathlen would overflow.
--         */
--        if (new_len < sp->fts_pathlen) {
--                free(sp->fts_path);
--                sp->fts_path = NULL;
--                __set_errno (ENAMETOOLONG);
--                return false;
--        }
--        sp->fts_pathlen = new_len;
--        char *p = realloc(sp->fts_path, sp->fts_pathlen);
--        if (p == NULL) {
--                free(sp->fts_path);
--                sp->fts_path = NULL;
--                return false;
--        }
--        sp->fts_path = p;
--        return true;
-+	char *p;
-+
-+	sp->fts_pathlen += more + 256;
-+	/*
-+	 * Check for possible wraparound.  In an FTS, fts_pathlen is
-+	 * a signed int but in an FTSENT it is an unsigned short.
-+	 * We limit fts_pathlen to USHRT_MAX to be safe in both cases.
-+	 */
-+	if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
-+		free(sp->fts_path);
-+		sp->fts_path = NULL;
-+		__set_errno (ENAMETOOLONG);
-+		return (1);
-+	}
-+	p = realloc(sp->fts_path, sp->fts_pathlen);
-+	if (p == NULL) {
-+		free(sp->fts_path);
-+		sp->fts_path = NULL;
-+		return 1;
-+	}
-+	sp->fts_path = p;
-+	return 0;
- }
- 
- /*
-- * When the file name is realloc'd, have to fix all of the pointers in
-- *  structures already returned.
-+ * When the path is realloc'd, have to fix all of the pointers in structures
-+ * already returned.
-  */
- static void
--internal_function
- fts_padjust (FTSOBJ *sp, FTSENTRY *head)
- {
--        char *addr = sp->fts_path;
--
--        /* This code looks at bit-patterns of freed pointers to
--           relocate them, so it relies on undefined behavior.  If this
--           trick does not work on your platform, please report a bug.  */
--
--#define ADJUST(p) do {                                                  \
--        uintptr_t old_accpath = (uintptr_t) (p)->fts_accpath;           \
--        if (old_accpath != (uintptr_t) (p)->fts_name) {                 \
--                (p)->fts_accpath =                                      \
--                  addr + (old_accpath - (uintptr_t) (p)->fts_path);     \
--        }                                                               \
--        (p)->fts_path = addr;                                           \
-+	FTSENTRY *p;
-+	char *addr = sp->fts_path;
-+
-+#define	ADJUST(p) do {							\
-+	if ((p)->fts_accpath != (p)->fts_name) {			\
-+		(p)->fts_accpath =					\
-+		    (char *)addr + ((p)->fts_accpath - (p)->fts_path);	\
-+	}								\
-+	(p)->fts_path = addr;						\
- } while (0)
--        /* Adjust the current set of children. */
--        for (FTSENTRY *p = sp->fts_child; p; p = p->fts_link)
--                ADJUST(p);
--
--        /* Adjust the rest of the tree, including the current level. */
--        for (FTSENTRY *p = head; p->fts_level >= FTS_ROOTLEVEL;) {
--                ADJUST(p);
--                p = p->fts_link ? p->fts_link : p->fts_parent;
--        }
-+	/* Adjust the current set of children. */
-+	for (p = sp->fts_child; p; p = p->fts_link)
-+		ADJUST(p);
-+
-+	/* Adjust the rest of the tree, including the current level. */
-+	for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
-+		ADJUST(p);
-+		p = p->fts_link ? p->fts_link : p->fts_parent;
-+	}
- }
- 
- static size_t
--internal_function _GL_ATTRIBUTE_PURE
- fts_maxarglen (char * const *argv)
- {
--        size_t max;
--
--        for (max = 0; *argv; ++argv) {
--                size_t len = strlen(*argv);
--                if (len > max)
--                        max = len;
--        }
--        return (max + 1);
-+	size_t len, max;
-+
-+	for (max = 0; *argv; ++argv)
-+		if ((len = strlen(*argv)) > max)
-+			max = len;
-+	return (max + 1);
- }
- 
- /*
-- * Change to dir specified by fd or file name without getting
-+ * Change to dir specified by fd or p->fts_accpath without getting
-  * tricked by someone changing the world out from underneath us.
-- * Assumes p->fts_statp->st_dev and p->fts_statp->st_ino are filled in.
-- * If FD is non-negative, expect it to be used after this function returns,
-- * and to be closed eventually.  So don't pass e.g., 'dirfd(dirp)' and then
-- * do closedir(dirp), because that would invalidate the saved FD.
-- * Upon failure, close FD immediately and return nonzero.
-+ * Assumes p->fts_dev and p->fts_ino are filled in.
-  */
- static int
--internal_function
--fts_safe_changedir (FTSOBJ *sp, FTSENTRY *p, int fd, char const *dir)
-+fts_safe_changedir (FTSOBJ *sp, FTSENTRY *p, int fd, const char *path)
- {
--        fts_assert (0 <= fd || dir != NULL);
--        bool is_dotdot = dir && streq (dir, "..");
--
--        /* This clause handles the unusual case in which FTS_NOCHDIR
--           is specified, along with FTS_CWDFD.  In that case, there is
--           no need to change even the virtual cwd file descriptor.
--           However, if FD is non-negative, we do close it here.  */
--        if (ISSET (FTS_NOCHDIR))
--          {
--            if (ISSET (FTS_CWDFD) && 0 <= fd)
--              close (fd);
--            return 0;
--          }
--
--        if (fd < 0 && is_dotdot && ISSET (FTS_CWDFD))
--          {
--            /* When possible, skip the diropen and subsequent fstat+dev/ino
--               comparison.  I.e., when changing to parent directory
--               (chdir ("..")), use a file descriptor from the ring and
--               save the overhead of diropen+fstat, as well as avoiding
--               failure when we lack "x" access to the virtual cwd.  */
--            if ( ! i_ring_empty (&sp->fts_fd_ring))
--              {
--                int parent_fd;
--                fd_ring_print (sp, stderr, "pre-pop");
--                parent_fd = i_ring_pop (&sp->fts_fd_ring);
--                if (0 <= parent_fd)
--                  {
--                    fd = parent_fd;
--                    dir = NULL;
--                  }
--              }
--          }
--
--        int newfd = fd;
--        if (fd < 0 && (newfd = diropen (sp, dir)) < 0)
--          return -1;
--
--        /* The following dev/inode check is necessary if we're doing a
--           "logical" traversal (through symlinks, a la chown -L), if the
--           system lacks O_NOFOLLOW support, or if we're changing to ".."
--           (but not via a popped file descriptor).  When changing to the
--           name "..", O_NOFOLLOW can't help.  In general, when the target is
--           not "..", diropen's use of O_NOFOLLOW ensures we don't mistakenly
--           follow a symlink, so we can avoid the expense of this fstat.  */
--        int ret;
--        if (ISSET(FTS_LOGICAL) || ! HAVE_WORKING_O_NOFOLLOW
--            || (dir && streq (dir, "..")))
--          {
--            struct STRUCT_STAT sb;
--            if (FSTAT (newfd, &sb))
--              {
--                ret = -1;
--                goto bail;
--              }
--            if (p->fts_statp->st_dev != sb.st_dev
--                || p->fts_statp->st_ino != sb.st_ino)
--              {
--                __set_errno (ENOENT);           /* disinformation */
--                ret = -1;
--                goto bail;
--              }
--          }
--
--        if (ISSET(FTS_CWDFD))
--          {
--            cwd_advance_fd (sp, newfd, ! is_dotdot);
--            return 0;
--          }
--
--        ret = fchdir(newfd);
-+	int ret, oerrno, newfd;
-+	struct STRUCT_STAT sb;
-+
-+	newfd = fd;
-+	if (ISSET(FTS_NOCHDIR))
-+		return (0);
-+	if (fd < 0 && (newfd = __open(path, O_RDONLY, 0)) < 0)
-+		return (-1);
-+	if (FSTAT (newfd, &sb)) {
-+		ret = -1;
-+		goto bail;
-+	}
-+	if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
-+		__set_errno (ENOENT);		/* disinformation */
-+		ret = -1;
-+		goto bail;
-+	}
-+	ret = __fchdir(newfd);
- bail:
--        if (fd < 0)
--          {
--            int oerrno = errno;
--            (void)close(newfd);
--            __set_errno (oerrno);
--          }
--        return ret;
-+	oerrno = errno;
-+	if (fd < 0)
-+		(void)__close(newfd);
-+	__set_errno (oerrno);
-+	return (ret);
- }
-diff --git a/io/fts.h b/io/fts.h
-index 50636e6c87a3a48d..b496e75ceeab0c3e 100644
---- a/io/fts.h
-+++ b/io/fts.h
-@@ -52,29 +52,7 @@
- 
- #include <features.h>
- #include <sys/types.h>
--#include <sys/stat.h>
--#include <dirent.h>
--#include <stdbool.h>
- 
--enum { __I_RING_SIZE = 4 };
--
--/* When ir_empty is true, the ring is empty.
--   Otherwise, ir_data[B..F] are defined, where B..F is the contiguous
--   range of indices, modulo I_RING_SIZE, from back to front, inclusive.
--   Undefined elements of ir_data are always set to ir_default_val.
--   Popping from an empty ring aborts.
--   Pushing onto a full ring returns the displaced value.
--   An empty ring has F==B and ir_empty == true.
--   A ring with one entry still has F==B, but now ir_empty == false.  */
--struct __I_ring
--{
--  int ir_data[__I_RING_SIZE];
--  int ir_default_val;
--  unsigned int ir_front;
--  unsigned int ir_back;
--  bool ir_empty;
--};
--typedef struct __I_ring __I_ring;
- 
- typedef struct {
- 	struct _ftsent *fts_cur;	/* current node */
-@@ -95,106 +73,11 @@ typedef struct {
- #define	FTS_SEEDOT	0x0020		/* return dot and dot-dot */
- #define	FTS_XDEV	0x0040		/* don't cross devices */
- #define FTS_WHITEOUT	0x0080		/* return whiteout information */
--
--  /* There are two ways to detect cycles.
--     The lazy way (which works only with FTS_PHYSICAL),
--     with which one may process a directory that is a
--     part of the cycle several times before detecting the cycle.
--     The "tight" way, whereby fts uses more memory (proportional
--     to number of "active" directories, aka distance from root
--     of current tree to current directory -- see active_dir_ht)
--     to detect any cycle right away.  For example, du must use
--     this option to avoid counting disk space in a cycle multiple
--     times, but chown -R need not.
--     The default is to use the constant-memory lazy way, when possible
--     (see below).
--
--     However, with FTS_LOGICAL (when following symlinks, e.g., chown -L)
--     using lazy cycle detection is inadequate.  For example, traversing
--     a directory containing a symbolic link to a peer directory, it is
--     possible to encounter the same directory twice even though there
--     is no cycle:
--     dir
--     ...
--     slink -> dir
--     So, when FTS_LOGICAL is selected, we have to use a different
--     mode of cycle detection: FTS_TIGHT_CYCLE_CHECK.  */
--#define FTS_TIGHT_CYCLE_CHECK	0x0400
--
--  /* Use this flag to enable semantics with which the parent
--     application may be made both more efficient and more robust.
--     Whereas the default is to visit each directory in a recursive
--     traversal (via chdir), using this flag makes it so the initial
--     working directory is never changed.  Instead, these functions
--     perform the traversal via a virtual working directory, maintained
--     through the file descriptor member, fts_cwd_fd.  */
--# define FTS_CWDFD              0x0800
--
--  /* Historically, for each directory that fts initially encounters, it would
--     open it, read all entries, and stat each entry, storing the results, and
--     then it would process the first entry.  But that behavior is bad for
--     locality of reference, and also causes trouble with inode-simulating
--     file systems like FAT, CIFS, FUSE-based ones, etc., when entries from
--     their name/inode cache are flushed too early.
--     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.  */
--#define FTS_DEFER_STAT	0x1000
--
--  /* Use this flag to disable stripping of trailing slashes
--     from input path names during fts_open initialization.  */
--#define FTS_VERBATIM	0x2000
--
--#define FTS_MOUNT       0x4000          /* skip other devices */
--#define FTS_OPTIONMASK  0x7fff          /* valid user option mask */
-+#define	FTS_OPTIONMASK	0x00ff		/* valid user option mask */
- 
- #define	FTS_NAMEONLY	0x0100		/* (private) child names only */
- #define	FTS_STOP	0x0200		/* (private) unrecoverable error */
--
- 	int fts_options;		/* fts_open options, global flags */
--
--	int fts_cwd_fd;                 /* the file descriptor on which the
--	                                   virtual cwd is open, or AT_FDCWD */
--
--	/* Map a directory's device number to a boolean.  The boolean is
--	   true if for that file system (type determined by a single fstatfs
--	   call per FS) st_nlink can be used to calculate the number of
--	   sub-directory entries in a directory.
--	   Using this table is an optimization that permits us to look up
--	   file system type on a per-inode basis at the minimal cost of
--	   calling fstatfs only once per traversed device.  */
--	struct hash_table *fts_leaf_optimization_works_ht;
--
--	union {
--	        /* This data structure is used if FTS_TIGHT_CYCLE_CHECK is
--	           specified.  It records the directories between a starting
--	           point and the current directory.  I.e., a directory is
--	           recorded here IFF we have visited it once, but we have not
--	           yet completed processing of all its entries.  Every time we
--	           visit a new directory, we add that directory to this set.
--	           When we finish with a directory (usually by visiting it a
--	           second time), we remove it from this set.  Each entry in
--	           this data structure is a device/inode pair.  This data
--	           structure is used to detect directory cycles efficiently and
--	           promptly even when the depth of a hierarchy is in the tens
--	           of thousands.  */
--	        struct hash_table *ht;
--
--	        /* FIXME: rename these two members to have the fts_ prefix */
--	        /* This data structure uses a lazy cycle-detection algorithm,
--	           as done by rm via cycle-check.c.  It's the default,
--	           but it's not appropriate for programs like du.  */
--	        struct cycle_check_state *state;
--	} fts_cycle;
--
--	/* A stack of the file descriptors corresponding to the
--	   most-recently traversed parent directories.
--	   Currently used only in FTS_CWDFD mode.  */
--	__I_ring fts_fd_ring;
- } FTS;
- 
- #ifdef __USE_LARGEFILE64
-@@ -209,13 +92,6 @@ typedef struct {
- 	int fts_nitems;			/* elements in the sort array */
- 	int (*fts_compar) (const void *, const void *); /* compare fn */
- 	int fts_options;		/* fts_open options, global flags */
--	int fts_cwd_fd;
--	struct hash_table *fts_leaf_optimization_works_ht;
--	union {
--	        struct hash_table *ht;
--	        struct cycle_check_state *state;
--	} fts_cycle;
--	__I_ring fts_fd_ring;
- } FTS64;
- #endif
- 
-diff --git a/io/fts64-time64.c b/io/fts64-time64.c
-index 6a1053194eec51ba..f9bad60572605dcb 100644
---- a/io/fts64-time64.c
-+++ b/io/fts64-time64.c
-@@ -19,19 +19,18 @@
- #include <time.h>
- 
- #if __TIMESIZE != 64
--# define FTS_OPEN           __fts64_open_time64
--# define FTS_CLOSE          __fts64_close_time64
--# define FTS_READ           __fts64_read_time64
--# define FTS_SET            __fts64_set_time64
--# define FTS_CHILDREN       __fts64_children_time64
--# define FTSOBJ             FTS64_TIME64
--# define FTSENTRY           FSTENT64_TIME64
--# define INO_T              ino64_t
--# define STRUCT_STAT        __stat64_t64
--# define FSTAT              __fstat64_time64
--# define FSTATAT            __fstatat64_time64
--# define STRUCT_STATFS      statfs64
--# define FSTATFS            __fstatfs64
-+# define FTS_OPEN __fts64_open_time64
-+# define FTS_CLOSE __fts64_close_time64
-+# define FTS_READ __fts64_read_time64
-+# define FTS_SET __fts64_set_time64
-+# define FTS_CHILDREN __fts64_children_time64
-+# define FTSOBJ FTS64_TIME64
-+# define FTSENTRY FSTENT64_TIME64
-+# define INO_T ino64_t
-+# define STRUCT_STAT __stat64_t64
-+# define STAT __stat64_time64
-+# define LSTAT __lstat64_time64
-+# define FSTAT __fstat64_time64
- 
- # include "fts.c"
- #endif
-diff --git a/io/fts64.c b/io/fts64.c
-index a6f607a87383f4a7..152910018e261049 100644
---- a/io/fts64.c
-+++ b/io/fts64.c
-@@ -25,9 +25,8 @@
- #define FTSENTRY FTSENT64
- #define INO_T ino64_t
- #define STRUCT_STAT stat64
-+#define STAT __stat64
-+#define LSTAT __lstat64
- #define FSTAT __fstat64
--#define FSTATAT __fstatat64
--#define STRUCT_STATFS statfs64
--#define FSTATFS __fstatfs64
- 
- #include "fts.c"
-diff --git a/io/i-ring.c b/io/i-ring.c
-deleted file mode 100644
-index b4e47904dd1af4e5..0000000000000000
---- a/io/i-ring.c
-+++ /dev/null
-@@ -1,72 +0,0 @@
--/* a simple ring buffer
--   Copyright (C) 2006, 2009-2026 Free Software Foundation, Inc.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--/* written by Jim Meyering */
--
--#include <config.h>
--#if !_LIBC
--# include "i-ring.h"
--# define INTERNAL_DEF
--#else
--# define I_ring __I_ring
--# define I_RING_SIZE __I_RING_SIZE
--#endif
--
--#include <stdlib.h>
--
--INTERNAL_DEF void
--i_ring_init (I_ring *ir, int default_val)
--{
--  ir->ir_empty = true;
--  ir->ir_front = 0;
--  ir->ir_back = 0;
--  for (int i = 0; i < I_RING_SIZE; i++)
--    ir->ir_data[i] = default_val;
--  ir->ir_default_val = default_val;
--}
--
--INTERNAL_DEF bool
--i_ring_empty (I_ring const *ir)
--{
--  return ir->ir_empty;
--}
--
--INTERNAL_DEF int
--i_ring_push (I_ring *ir, int val)
--{
--  unsigned int dest_idx = (ir->ir_front + !ir->ir_empty) % I_RING_SIZE;
--  int old_val = ir->ir_data[dest_idx];
--  ir->ir_data[dest_idx] = val;
--  ir->ir_front = dest_idx;
--  if (dest_idx == ir->ir_back)
--    ir->ir_back = (ir->ir_back + !ir->ir_empty) % I_RING_SIZE;
--  ir->ir_empty = false;
--  return old_val;
--}
--
--INTERNAL_DEF int
--i_ring_pop (I_ring *ir)
--{
--  if (i_ring_empty (ir))
--    abort ();
--  int top_val = ir->ir_data[ir->ir_front];
--  ir->ir_data[ir->ir_front] = ir->ir_default_val;
--  if (ir->ir_front == ir->ir_back)
--    ir->ir_empty = true;
--  else
--    ir->ir_front = ((ir->ir_front + I_RING_SIZE - 1) % I_RING_SIZE);
--  return top_val;
--}
-diff --git a/io/same-inode.h b/io/same-inode.h
-deleted file mode 100644
-index 44b6f3ed84e42e8c..0000000000000000
---- a/io/same-inode.h
-+++ /dev/null
-@@ -1,106 +0,0 @@
--/* Determine whether two stat buffers are known to refer to the same file.
--
--   Copyright (C) 2006, 2009-2026 Free Software Foundation, Inc.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--#ifndef SAME_INODE_H
--#define SAME_INODE_H 1
--
--/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE.  */
--#if !_LIBC && !_GL_CONFIG_H_INCLUDED
-- #error "Please include config.h first."
--#endif
--
--#include <sys/stat.h>
--#if _LIBC
--# define _GL_INLINE_HEADER_BEGIN
--# define _GL_INLINE_HEADER_END
--# define SAME_INODE_INLINE static inline
--# define S_TYPEISTMO(p) 0
--#endif
--
--_GL_INLINE_HEADER_BEGIN
--#ifndef SAME_INODE_INLINE
--# define SAME_INODE_INLINE _GL_INLINE
--#endif
--
--#ifdef __cplusplus
--extern "C" {
--#endif
--
--
--/* True if A and B point to structs with st_dev and st_ino members
--   that are known to represent the same file.
--
--   Use | and ^ to shorten generated code, and to lessen the
--   probability of screwups if st_ino is an array.  */
--
--#if defined __VMS && __CRTL_VER < 80200000
--# define PSAME_INODE(a, b) (! (((a)->st_dev ^ (b)->st_dev) \
--                               | ((a)->st_ino[0] ^ (b)->st_ino[0]) \
--                               | ((a)->st_ino[1] ^ (b)->st_ino[1]) \
--                               | ((a)->st_ino[2] ^ (b)->st_ino[2])))
--#elif defined _WIN32 && ! defined __CYGWIN__
--  /* Native Windows.  */
--# if _GL_WINDOWS_STAT_INODES
--  /* stat() and fstat() set st_dev and st_ino to 0 if information about
--     the inode is not available.  */
--#  if _GL_WINDOWS_STAT_INODES == 2
--#   define PSAME_INODE(a, b) \
--     (! (! ((a)->st_dev | (a)->st_ino._gl_ino[0] | (a)->st_ino._gl_ino[1]) \
--         | ((a)->st_dev ^ (b)->st_dev) \
--         | ((a)->st_ino._gl_ino[0] ^ (b)->st_ino._gl_ino[0]) \
--         | ((a)->st_ino._gl_ino[1] ^ (b)->st_ino._gl_ino[1])))
--#  else
--#   define PSAME_INODE(a, b) (! (! ((a)->st_dev | (a)->st_ino) \
--                                 | ((a)->st_dev ^ (b)->st_dev) \
--                                 | ((a)->st_ino ^ (b)->st_ino)))
--#  endif
--# else
--  /* stat() and fstat() set st_ino to 0 always.  */
--#  define PSAME_INODE(a, b) 0
--# endif
--#else
--  /* POSIX.  */
--# define PSAME_INODE(a, b) (! (((a)->st_dev ^ (b)->st_dev) \
--                               | ((a)->st_ino ^ (b)->st_ino)))
--#endif
--
--/* True if struct objects A and B are known to represent the same file.  */
--
--#define SAME_INODE(a, b) PSAME_INODE (&(a), &(b))
--
--/* True if *A and *B represent the same file.  Unlike PSAME_INODE,
--   args are evaluated once and must point to struct stat,
--   and this function works even on POSIX platforms where fstat etc. do
--   not return useful st_dev and st_ino values for shared memory
--   objects and typed memory objects.  */
--
--SAME_INODE_INLINE bool
--psame_inode (struct stat const *a, struct stat const *b)
--{
--  return (! (S_TYPEISSHM (a) | S_TYPEISTMO (a)
--             | S_TYPEISSHM (b) | S_TYPEISTMO (b))
--          && PSAME_INODE (a, b));
--}
--
--
--#ifdef __cplusplus
--}
--#endif
--
--_GL_INLINE_HEADER_END
--
--#endif
-diff --git a/io/tst-fts-bz22944.c b/io/tst-fts-bz22944.c
-deleted file mode 100644
-index 7f860452349b3c9e..0000000000000000
---- a/io/tst-fts-bz22944.c
-+++ /dev/null
-@@ -1,100 +0,0 @@
--/* Check that fts does not fail with very long paths.
--   Copyright (C) 2026 Free Software Foundation, Inc.
--   This file is part of the GNU C Library.
--
--   The GNU C Library is free software; you can redistribute it and/or
--   modify it under the terms of the GNU Lesser General Public
--   License as published by the Free Software Foundation; either
--   version 2.1 of the License, or (at your option) any later version.
--
--   The GNU C Library 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
--   Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public
--   License along with the GNU C Library; if not, see
--   <https://www.gnu.org/licenses/>.  */
--
--#include <fts.h>
--#include <errno.h>
--#include <stdio.h>
--#include <support/check.h>
--#include <support/temp_file.h>
--#include <support/xunistd.h>
--
--#define BASENAME "tst-fts-bz22944."
--
--enum { nested_depth = 150 };
--static const char dir_name[] = { [0 ... 254] = 'A', '\0' };
--
--static void
--do_cleanup (void)
--{
--  xchdir ("..");
--  for (int i = 0; i < nested_depth; i++)
--    {
--      remove (dir_name);
--      xchdir ("..");
--    }
--  remove (dir_name);
--}
--#define CLEANUP_HANDLER do_cleanup
--
--static void
--check_mkdir (const char *path)
--{
--  int r = mkdir (path, 0700);
--  /* Some filesystem such as overlayfs does not support larger path required
--     to trigger the internal buffer reallocation.  */
--  if (r != 0)
--    {
--      if (errno == ENAMETOOLONG)
--	FAIL_UNSUPPORTED ("the filesystem does not support the required"
--			  "large path");
--      else
--	FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", path, 0700);
--    }
--}
--
--int
--do_test (void)
--{
--  char *tempdir = support_create_temp_directory (BASENAME);
--  xchdir (tempdir);
--  for (int i = 0; i < nested_depth; i++)
--    {
--      check_mkdir (dir_name);
--      xchdir (dir_name);
--    }
--
--  char *paths[] = { tempdir , 0 };
--  FTS *ftsp = fts_open (paths, FTS_XDEV | FTS_COMFOLLOW | FTS_PHYSICAL, 0);
--  TEST_VERIFY_EXIT (ftsp != NULL);
--
--  int num_dirs = 0;
--
--  FTSENT *ent;
--  while ((ent = fts_read(ftsp)) != 0)
--    {
--      switch (ent->fts_info)
--	{
--	case FTS_D:
--	  num_dirs++;
--	  break;
--	default:
--	  break;
--	}
--    }
--
--  TEST_COMPARE (num_dirs, nested_depth + 1);
--  TEST_COMPARE (errno, 0);
--
--  fts_close (ftsp);
--
--  do_cleanup ();
--
--  return 0;
--}
--
--#include <support/test-driver.c>
-diff --git a/io/tst-fts-newflags.c b/io/tst-fts-newflags.c
-deleted file mode 100644
-index a40561268bb55914..0000000000000000
---- a/io/tst-fts-newflags.c
-+++ /dev/null
-@@ -1,234 +0,0 @@
--/* Simple tests for some gnulib imported fts features.
--   Copyright (C) 2026 Free Software Foundation, Inc.
--   This file is part of the GNU C Library.
--
--   The GNU C Library is free software; you can redistribute it and/or
--   modify it under the terms of the GNU Lesser General Public
--   License as published by the Free Software Foundation; either
--   version 2.1 of the License, or (at your option) any later version.
--
--   The GNU C Library 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
--   Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public
--   License along with the GNU C Library; if not, see
--   <https://www.gnu.org/licenses/>.  */
--
--#include <errno.h>
--#include <fts.h>
--#include <stdbool.h>
--#include <stdio.h>
--#include <stdlib.h>
--#include <fcntl.h>
--#include <string.h>
--#include <support/check.h>
--#include <support/support.h>
--#include <support/temp_file.h>
--#include <support/xunistd.h>
--
--static char *tempdir;
--
--static void
--do_prepare (int argc, char **argv)
--{
--  tempdir = support_create_temp_directory ("tst-fts-newflags");
--
--  /* Create directory tree:
--     tempdir/dir
--     tempdir/dir/file
--     tempdir/dir/symlink -> tempdir   (cycle)  */
--  char *path;
--
--  path = xasprintf ("%s/dir", tempdir);
--  xmkdir (path, 0777);
--  add_temp_file (path);
--  free (path);
--
--  path = xasprintf ("%s/dir/file", tempdir);
--  int fd = xopen (path, O_CREAT | O_RDWR, 0666);
--  xclose (fd);
--  add_temp_file (path);
--  free (path);
--
--  path = xasprintf ("%s/dir/symlink", tempdir);
--  xsymlink (tempdir, path);
--  add_temp_file (path);
--  free (path);
--}
--#define PREPARE do_prepare
--
--/* FTS_TIGHT_CYCLE_CHECK:  we use FTS_LOGICAL to follow the symlink we
--   created, causing a loop.  The tight cycle checker should catch this
--   immediately and emit FTS_DC.  */
--static void
--test_tight_cycle (void)
--{
--  char *paths[] = { tempdir, NULL };
--  FTS *fts = fts_open (paths, FTS_LOGICAL | FTS_TIGHT_CYCLE_CHECK, NULL);
--  TEST_VERIFY_EXIT (fts != NULL);
--
--  FTSENT *ent;
--  bool found_cycle = false;
--  while ((ent = fts_read (fts)) != NULL)
--    {
--      if (ent->fts_info == FTS_DC)
--        {
--          found_cycle = true;
--          break;
--        }
--    }
--  TEST_VERIFY (found_cycle);
--  fts_close (fts);
--}
--
--/* FTS_CWDFD: ensures that fts uses virtual file descriptors and does not
--   actually change the process's global working directory.  */
--static void
--test_cwdfd (void)
--{
--  char *paths[] = { tempdir, NULL };
--  FTS *fts = fts_open (paths, FTS_PHYSICAL | FTS_CWDFD, NULL);
--  TEST_VERIFY_EXIT (fts != NULL);
--
--  char *cwd_before = getcwd (NULL, 0);
--  TEST_VERIFY_EXIT (cwd_before != NULL);
--
--  FTSENT *ent;
--  while ((ent = fts_read (fts)) != NULL)
--    {
--    }
--
--  char *cwd_after = getcwd (NULL, 0);
--  TEST_VERIFY_EXIT (cwd_after != NULL);
--
--  /* If FTS_CWDFD works, the global CWD remains untouched.  */
--  TEST_COMPARE_STRING (cwd_before, cwd_after);
--
--  free (cwd_before);
--  free (cwd_after);
--  fts_close (fts);
--}
--
--/* FTS_DEFER_STAT: verifies that deferring the stat calls does not break
--   standard physical tree traversals.  */
--static void
--test_defer_stat (void)
--{
--  char *paths[] = { tempdir, NULL };
--  FTS *fts = fts_open (paths, FTS_PHYSICAL | FTS_DEFER_STAT, NULL);
--  TEST_VERIFY_EXIT (fts != NULL);
--
--  FTSENT *ent;
--  int count = 0;
--  while ((ent = fts_read (fts)) != NULL)
--    {
--      count++;
--    }
--
--  /* Expects:
--
--     1: $tmpdir
--     2: $tmpdir/dir
--     3: $tmpdir/dir/file
--     4: $tmpdir/dir/symlink
--     5: $tmpdir/dir/
--     6: $tmpdir/  */
--  TEST_COMPARE (count, 6);
--  fts_close (fts);
--}
--
--/* FTS_MOUNT: validates that the traversal refuses to cross into a different
--   file system when the flag is set. Assumes /proc is on a different mount.  */
--static void
--test_mount (void)
--{
--  /* Create a symlink to /proc, which resides on a different mount point. */
--  char *link_path = xasprintf ("%s/mnt_link", tempdir);
--  xsymlink ("/proc", link_path);
--
--  /* Traverse with FTS_LOGICAL so fts resolves the symlink and sees the
--     /proc device ID, but add FTS_MOUNT to enforce the boundary. */
--  char *paths[] = { tempdir, NULL };
--  FTS *fts = fts_open (paths, FTS_LOGICAL | FTS_MOUNT, NULL);
--  TEST_VERIFY_EXIT (fts != NULL);
--
--  FTSENT *ent;
--  bool found_mnt_link = false;
--  while ((ent = fts_read (fts)) != NULL)
--    {
--      if (strcmp (ent->fts_name, "mnt_link") == 0)
--        found_mnt_link = true;
--    }
--
--  /* Because the device ID of /proc differs from the root traversal
--     device ID, FTS_MOUNT forces fts to skip the entry entirely. */
--  TEST_VERIFY (!found_mnt_link);
--
--  fts_close (fts);
--  unlink (link_path);
--  free (link_path);
--}
--
--/* FTS_VERBATIM: Ensures paths are passed through without having trailing
--   slashes stripped.  */
--static void
--test_verbatim (void)
--{
--  char *path_with_slashes = xasprintf ("%s///", tempdir);
--  char *paths[] = { path_with_slashes, NULL };
--
--  FTS *fts = fts_open (paths, FTS_PHYSICAL | FTS_VERBATIM, NULL);
--  TEST_VERIFY_EXIT (fts != NULL);
--
--  FTSENT *ent = fts_read (fts);
--  TEST_VERIFY_EXIT (ent != NULL);
--
--  /* The returned root path should retain the exact slashes passed to it. */
--  TEST_COMPARE_STRING (ent->fts_path, path_with_slashes);
--
--  fts_close (fts);
--  free (path_with_slashes);
--}
--
--/* Main test driver */
--static int
--do_test (void)
--{
--  support_need_proc ("FTS_MOUNT test requires /proc");
--
--  {
--    /* Check if fts_open does not fail if neither FTS_LOGICAL nor FTS_PHYSICAL
--       are specified.  */
--    char *paths[] = { tempdir, NULL };
--    FTS *fts = fts_open (paths, 0, NULL);
--    TEST_VERIFY_EXIT (fts != NULL);
--    fts_close (fts);
--  }
--
--  {
--    FTS *fts;
--    char *paths[] = { tempdir, NULL };
--
--    /* There are internal only flags.  */
--    fts = fts_open (paths, FTS_NAMEONLY, NULL);
--    TEST_VERIFY_EXIT (fts == NULL);
--    TEST_COMPARE (errno, EINVAL);
--
--    fts = fts_open (paths, FTS_STOP, NULL);
--    TEST_VERIFY_EXIT (fts == NULL);
--    TEST_COMPARE (errno, EINVAL);
--  }
--
--  test_tight_cycle ();
--  test_cwdfd ();
--  test_defer_stat ();
--  test_mount ();
--  test_verbatim ();
--
--  return 0;
--}
--
--/* Includes the glibc test framework driver */
--#include <support/test-driver.c>
-diff --git a/io/tst-fts.c b/io/tst-fts.c
-index ca82377d20c26efb..494eb29c9a7fdd95 100644
---- a/io/tst-fts.c
-+++ b/io/tst-fts.c
-@@ -192,8 +192,6 @@ do_test (void)
-      don't use FTS_LOGICAL.  */
- #ifndef TST_FTS_Y2038
-   flags |= FTS_LOGICAL;
--#else
--  flags |= FTS_PHYSICAL;
- #endif
-   fts = fts_open (paths, flags, &compare_ents);
-   if (fts == NULL)
-diff --git a/misc/Makefile b/misc/Makefile
-index 4395366d74c12fcc..fc44de99348f5ceb 100644
---- a/misc/Makefile
-+++ b/misc/Makefile
-@@ -121,7 +121,6 @@ routines := \
-   getusershell \
-   getxattr \
-   gtty \
--  hash \
-   hsearch \
-   hsearch_r \
-   ifunc-impl-list \
-@@ -158,7 +157,6 @@ routines := \
-   munlock \
-   munlockall \
-   munmap \
--  next-prime \
-   preadv \
-   preadv2 \
-   preadv64 \
-diff --git a/misc/hash.c b/misc/hash.c
-deleted file mode 100644
-index f722713a8fb01796..0000000000000000
---- a/misc/hash.c
-+++ /dev/null
-@@ -1,1045 +0,0 @@
--/* hash - hashing table processing.
--
--   Copyright (C) 1998-2004, 2006-2007, 2009-2026 Free Software Foundation, Inc.
--
--   Written by Jim Meyering, 1992.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--/* A generic hash table package.  */
--
--/* Define USE_OBSTACK to 1 if you want the allocator to use obstacks instead
--   of malloc.  If you change USE_OBSTACK, you have to recompile!  */
--
--#include <config.h>
--#ifdef _LIBC
--# define USE_OBSTACK           0
--# define TESTING               0
--# include <stdbit.h>
--# define rotr_sz(__x, __n)     stdc_rotate_right(__x, __n)
--#else
--# include "bitrotate.h"
--#endif
--
--#include "hash.h"
--
--#include "next-prime.h"
--#include "xalloc-oversized.h"
--
--#include <errno.h>
--#include <stdint.h>
--#include <stdio.h>
--#include <stdlib.h>
--
--#if USE_OBSTACK
--# include "obstack.h"
--# ifndef obstack_chunk_alloc
--#  define obstack_chunk_alloc malloc
--# endif
--# ifndef obstack_chunk_free
--#  define obstack_chunk_free free
--# endif
--#endif
--
--struct hash_entry
--  {
--    void *data;
--    struct hash_entry *next;
--    /* Invariant: If DATA is NULL, this entry is an unused bucket head,
--       and therefore NEXT is NULL as well.  */
--  };
--
--struct hash_table
--  {
--    /* The array of buckets starts at BUCKET and extends to BUCKET_LIMIT-1,
--       for a possibility of N_BUCKETS.  Among those, N_BUCKETS_USED buckets
--       are not empty, there are N_ENTRIES active entries in the table.  */
--    struct hash_entry *bucket;
--    struct hash_entry const *bucket_limit;
--    size_t n_buckets;
--    size_t n_buckets_used;
--    size_t n_entries;
--
--    /* Tuning arguments, kept in a physically separate structure.  */
--    const Hash_tuning *tuning;
--
--    /* Three functions are given to 'hash_initialize', see the documentation
--       block for this function.  In a word, HASHER randomizes a user entry
--       into a number up from 0 up to some maximum minus 1; COMPARATOR returns
--       true if two user entries compare equally; and DATA_FREER is the cleanup
--       function for a user entry.  */
--    Hash_hasher hasher;
--    Hash_comparator comparator;
--    Hash_data_freer data_freer;
--
--    /* A linked list of freed struct hash_entry structs.  */
--    struct hash_entry *free_entry_list;
--
--#if USE_OBSTACK
--    /* Whenever obstacks are used, it is possible to allocate all overflowed
--       entries into a single stack, so they all can be freed in a single
--       operation.  It is not clear if the speedup is worth the trouble.  */
--    struct obstack entry_stack;
--#endif
--  };
--
--/* A hash table contains many internal entries, each holding a pointer to
--   some user-provided data (also called a user entry).  An entry indistinctly
--   refers to both the internal entry and its associated user entry.  A user
--   entry contents may be hashed by a randomization function (the hashing
--   function, or just "hasher" for short) into a number (or "slot") between 0
--   and the current table size.  At each slot position in the hash table,
--   starts a linked chain of entries for which the user data all hash to this
--   slot.  A bucket is the collection of all entries hashing to the same slot.
--
--   A good "hasher" function will distribute entries rather evenly in buckets.
--   In the ideal case, the length of each bucket is roughly the number of
--   entries divided by the table size.  Finding the slot for a data is usually
--   done in constant time by the "hasher", and the later finding of a precise
--   entry is linear in time with the size of the bucket.  Consequently, a
--   larger hash table size (that is, a larger number of buckets) is prone to
--   yielding shorter chains, *given* the "hasher" function behaves properly.
--
--   Long buckets slow down the lookup algorithm.  One might use big hash table
--   sizes in hope to reduce the average length of buckets, but this might
--   become inordinate, as unused slots in the hash table take some space.  The
--   best bet is to make sure you are using a good "hasher" function (beware
--   that those are not that easy to write! :-), and to use a table size
--   larger than the actual number of entries.  */
--
--/* If an insertion makes the ratio of nonempty buckets to table size larger
--   than the growth threshold (a number between 0.0 and 1.0), then increase
--   the table size by multiplying by the growth factor (a number greater than
--   1.0).  The growth threshold defaults to 0.8, and the growth factor
--   defaults to 1.414, meaning that the table will have doubled its size
--   every second time 80% of the buckets get used.  */
--#define DEFAULT_GROWTH_THRESHOLD 0.8f
--#define DEFAULT_GROWTH_FACTOR 1.414f
--
--/* If a deletion empties a bucket and causes the ratio of used buckets to
--   table size to become smaller than the shrink threshold (a number between
--   0.0 and 1.0), then shrink the table by multiplying by the shrink factor (a
--   number greater than the shrink threshold but smaller than 1.0).  The shrink
--   threshold and factor default to 0.0 and 1.0, meaning that the table never
--   shrinks.  */
--#define DEFAULT_SHRINK_THRESHOLD 0.0f
--#define DEFAULT_SHRINK_FACTOR 1.0f
--
--/* Use this to initialize or reset a TUNING structure to
--   some sensible values. */
--static const Hash_tuning default_tuning =
--  {
--    DEFAULT_SHRINK_THRESHOLD,
--    DEFAULT_SHRINK_FACTOR,
--    DEFAULT_GROWTH_THRESHOLD,
--    DEFAULT_GROWTH_FACTOR,
--    false
--  };
--
--/* Information and lookup.  */
--
--#if !_LIBC
--size_t
--hash_get_n_buckets (const Hash_table *table)
--{
--  return table->n_buckets;
--}
--
--size_t
--hash_get_n_buckets_used (const Hash_table *table)
--{
--  return table->n_buckets_used;
--}
--
--size_t
--hash_get_n_entries (const Hash_table *table)
--{
--  return table->n_entries;
--}
--
--size_t
--hash_get_max_bucket_length (const Hash_table *table)
--{
--  size_t max_bucket_length = 0;
--
--  for (struct hash_entry const *bucket = table->bucket;
--       bucket < table->bucket_limit;
--       bucket++)
--    {
--      if (bucket->data)
--        {
--          struct hash_entry const *cursor = bucket;
--          size_t bucket_length = 1;
--
--          while (cursor = cursor->next, cursor)
--            bucket_length++;
--
--          if (bucket_length > max_bucket_length)
--            max_bucket_length = bucket_length;
--        }
--    }
--
--  return max_bucket_length;
--}
--
--bool
--hash_table_ok (const Hash_table *table)
--{
--  size_t n_buckets_used = 0;
--  size_t n_entries = 0;
--
--  for (struct hash_entry const *bucket = table->bucket;
--       bucket < table->bucket_limit;
--       bucket++)
--    {
--      if (bucket->data)
--        {
--          struct hash_entry const *cursor = bucket;
--
--          /* Count bucket head.  */
--          n_buckets_used++;
--          n_entries++;
--
--          /* Count bucket overflow.  */
--          while (cursor = cursor->next, cursor)
--            n_entries++;
--        }
--    }
--
--  if (n_buckets_used == table->n_buckets_used && n_entries == table->n_entries)
--    return true;
--
--  return false;
--}
--
--void
--hash_print_statistics (const Hash_table *table, FILE *stream)
--{
--  size_t n_entries = hash_get_n_entries (table);
--  size_t n_buckets = hash_get_n_buckets (table);
--  size_t n_buckets_used = hash_get_n_buckets_used (table);
--  size_t max_bucket_length = hash_get_max_bucket_length (table);
--
--  fprintf (stream, "# entries:         %lu\n", (unsigned long int) n_entries);
--  fprintf (stream, "# buckets:         %lu\n", (unsigned long int) n_buckets);
--  fprintf (stream, "# buckets used:    %lu (%.2f%%)\n",
--           (unsigned long int) n_buckets_used,
--           (100.0 * n_buckets_used) / n_buckets);
--  fprintf (stream, "max bucket length: %lu\n",
--           (unsigned long int) max_bucket_length);
--}
--#endif
--
--/* Hash KEY and return a pointer to the selected bucket.
--   If TABLE->hasher misbehaves, abort.  */
--static struct hash_entry *
--safe_hasher (const Hash_table *table, const void *key)
--{
--  size_t n = table->hasher (key, table->n_buckets);
--  if (! (n < table->n_buckets))
--    abort ();
--  return table->bucket + n;
--}
--
--void *
--hash_lookup (const Hash_table *table, const void *entry)
--{
--  struct hash_entry const *bucket = safe_hasher (table, entry);
--
--  if (bucket->data == NULL)
--    return NULL;
--
--  for (struct hash_entry const *cursor = bucket; cursor; cursor = cursor->next)
--    if (entry == cursor->data || table->comparator (entry, cursor->data))
--      return cursor->data;
--
--  return NULL;
--}
--
--#if !_LIBC
--/* Walking.  */
--
--void *
--hash_get_first (const Hash_table *table)
--{
--  if (table->n_entries == 0)
--    return NULL;
--
--  for (struct hash_entry const *bucket = table->bucket; ; bucket++)
--    if (! (bucket < table->bucket_limit))
--      abort ();
--    else if (bucket->data)
--      return bucket->data;
--}
--
--void *
--hash_get_next (const Hash_table *table, const void *entry)
--{
--  struct hash_entry const *bucket = safe_hasher (table, entry);
--
--  /* Find next entry in the same bucket.  */
--  {
--    struct hash_entry const *cursor = bucket;
--    do
--      {
--        if (cursor->data == entry && cursor->next)
--          return cursor->next->data;
--        cursor = cursor->next;
--      }
--    while (cursor != NULL);
--  }
--
--  /* Find first entry in any subsequent bucket.  */
--  while (++bucket < table->bucket_limit)
--    if (bucket->data)
--      return bucket->data;
--
--  /* None found.  */
--  return NULL;
--}
--
--size_t
--hash_get_entries (const Hash_table *table, void **buffer,
--                  size_t buffer_size)
--{
--  size_t counter = 0;
--
--  for (struct hash_entry const *bucket = table->bucket;
--       bucket < table->bucket_limit;
--       bucket++)
--    {
--      if (bucket->data)
--        {
--          for (struct hash_entry const *cursor = bucket; cursor; cursor = cursor->next)
--            {
--              if (counter >= buffer_size)
--                return counter;
--              buffer[counter++] = cursor->data;
--            }
--        }
--    }
--
--  return counter;
--}
--
--size_t
--hash_do_for_each (const Hash_table *table, Hash_processor processor,
--                  void *processor_data)
--{
--  size_t counter = 0;
--
--  for (struct hash_entry const *bucket = table->bucket;
--       bucket < table->bucket_limit;
--       bucket++)
--    {
--      if (bucket->data)
--        {
--          for (struct hash_entry const *cursor = bucket; cursor; cursor = cursor->next)
--            {
--              if (! processor (cursor->data, processor_data))
--                return counter;
--              counter++;
--            }
--        }
--    }
--
--  return counter;
--}
--#endif
--
--
--/* If the user passes a NULL hasher, we hash the raw pointer.  */
--static size_t
--raw_hasher (const void *data, size_t n)
--{
--  /* When hashing unique pointers, it is often the case that they were
--     generated by malloc and thus have the property that the low-order
--     bits are 0.  As this tends to give poorer performance with small
--     tables, we rotate the pointer value before performing division,
--     in an attempt to improve hash quality.  */
--  size_t val = rotr_sz ((size_t) data, 3);
--  return val % n;
--}
--
--/* If the user passes a NULL comparator, we use pointer comparison.  */
--static bool
--raw_comparator (const void *a, const void *b)
--{
--  return a == b;
--}
--
--
--#if !_LIBC
--/* Allocation and clean-up.  */
--
--void
--hash_reset_tuning (Hash_tuning *tuning)
--{
--  *tuning = default_tuning;
--}
--#endif
--
--/* For the given hash TABLE, check the user supplied tuning structure for
--   reasonable values, and return true if there is no gross error with it.
--   Otherwise, definitively reset the TUNING field to some acceptable default
--   in the hash table (that is, the user loses the right of further modifying
--   tuning arguments), and return false.  */
--
--static bool
--check_tuning (Hash_table *table)
--{
--  const Hash_tuning *tuning = table->tuning;
--  if (tuning == &default_tuning)
--    return true;
--
--  /* Be a bit stricter than mathematics would require, so that
--     rounding errors in size calculations do not cause allocations to
--     fail to grow or shrink as they should.  The smallest allocation
--     is 11 (due to next_prime's algorithm), so an epsilon of 0.1
--     should be good enough.  */
--  float epsilon = 0.1f;
--
--  if (epsilon < tuning->growth_threshold
--      && tuning->growth_threshold < 1 - epsilon
--      && 1 + epsilon < tuning->growth_factor
--      && 0 <= tuning->shrink_threshold
--      && tuning->shrink_threshold + epsilon < tuning->shrink_factor
--      && tuning->shrink_factor <= 1
--      && tuning->shrink_threshold + epsilon < tuning->growth_threshold)
--    return true;
--
--  table->tuning = &default_tuning;
--  return false;
--}
--
--/* Compute the size of the bucket array for the given CANDIDATE and
--   TUNING, or return 0 if there is no possible way to allocate that
--   many entries.  */
--
--static size_t _GL_ATTRIBUTE_PURE
--compute_bucket_size (size_t candidate, const Hash_tuning *tuning)
--{
--  if (!tuning->is_n_buckets)
--    {
--      float new_candidate = candidate / tuning->growth_threshold;
--      if ((float) SIZE_MAX <= new_candidate)
--        goto nomem;
--      candidate = new_candidate;
--    }
--  candidate = next_prime (candidate);
--  if (xalloc_oversized (candidate, sizeof (struct hash_entry *)))
--    goto nomem;
--  return candidate;
--
-- nomem:
--  errno = ENOMEM;
--  return 0;
--}
--
--Hash_table *
--hash_initialize (size_t candidate, const Hash_tuning *tuning,
--                 Hash_hasher hasher, Hash_comparator comparator,
--                 Hash_data_freer data_freer)
--{
--  if (hasher == NULL)
--    hasher = raw_hasher;
--  if (comparator == NULL)
--    comparator = raw_comparator;
--
--  Hash_table *table = malloc (sizeof *table);
--  if (table == NULL)
--    return NULL;
--
--  if (!tuning)
--    tuning = &default_tuning;
--  table->tuning = tuning;
--  if (!check_tuning (table))
--    {
--      /* Fail if the tuning options are invalid.  This is the only occasion
--         when the user gets some feedback about it.  Once the table is created,
--         if the user provides invalid tuning options, we silently revert to
--         using the defaults, and ignore further request to change the tuning
--         options.  */
--      errno = EINVAL;
--      goto fail;
--    }
--
--  table->n_buckets = compute_bucket_size (candidate, tuning);
--  if (!table->n_buckets)
--    goto fail;
--
--  table->bucket = calloc (table->n_buckets, sizeof *table->bucket);
--  if (table->bucket == NULL)
--    goto fail;
--  table->bucket_limit = table->bucket + table->n_buckets;
--  table->n_buckets_used = 0;
--  table->n_entries = 0;
--
--  table->hasher = hasher;
--  table->comparator = comparator;
--  table->data_freer = data_freer;
--
--  table->free_entry_list = NULL;
--#if USE_OBSTACK
--  obstack_init (&table->entry_stack);
--#endif
--  return table;
--
-- fail:
--  free (table);
--  return NULL;
--}
--
--#if !_LIBC
--void
--hash_clear (Hash_table *table)
--{
--  for (struct hash_entry *bucket = table->bucket;
--       bucket < table->bucket_limit;
--       bucket++)
--    {
--      if (bucket->data)
--        {
--          /* Free the bucket overflow.  */
--          for (struct hash_entry *cursor = bucket->next; cursor; )
--            {
--              if (table->data_freer)
--                table->data_freer (cursor->data);
--              cursor->data = NULL;
--
--              struct hash_entry *next = cursor->next;
--              /* Relinking is done one entry at a time, as it is to be expected
--                 that overflows are either rare or short.  */
--              cursor->next = table->free_entry_list;
--              table->free_entry_list = cursor;
--
--              cursor = next;
--            }
--
--          /* Free the bucket head.  */
--          if (table->data_freer)
--            table->data_freer (bucket->data);
--          bucket->data = NULL;
--          bucket->next = NULL;
--        }
--    }
--
--  table->n_buckets_used = 0;
--  table->n_entries = 0;
--}
--#endif
--
--void
--hash_free (Hash_table *table)
--{
--  int saved_errno = errno;
--
--  /* Call the user data_freer function.  */
--  if (table->data_freer && table->n_entries)
--    {
--      for (struct hash_entry *bucket = table->bucket;
--           bucket < table->bucket_limit;
--           bucket++)
--        {
--          if (bucket->data)
--            {
--              for (struct hash_entry *cursor = bucket; cursor; cursor = cursor->next)
--                table->data_freer (cursor->data);
--            }
--        }
--    }
--
--#if USE_OBSTACK
--
--  obstack_free (&table->entry_stack, NULL);
--
--#else
--
--  /* Free all bucket overflowed entries.  */
--  for (struct hash_entry *bucket = table->bucket;
--       bucket < table->bucket_limit;
--       bucket++)
--    {
--      for (struct hash_entry *cursor = bucket->next; cursor; )
--        {
--          struct hash_entry *next = cursor->next;
--          free (cursor);
--          cursor = next;
--        }
--    }
--
--  /* Also reclaim the internal list of previously freed entries.  */
--  for (struct hash_entry *cursor = table->free_entry_list; cursor; )
--    {
--      struct hash_entry *next = cursor->next;
--      free (cursor);
--      cursor = next;
--    }
--
--#endif
--
--  /* Free the remainder of the hash table structure.  */
--  free (table->bucket);
--  free (table);
--
--  errno = saved_errno;
--}
--
--/* Insertion and deletion.  */
--
--/* Get a new hash entry for a bucket overflow, possibly by recycling a
--   previously freed one.  If this is not possible, allocate a new one.  */
--
--static struct hash_entry *
--allocate_entry (Hash_table *table)
--{
--  struct hash_entry *new;
--
--  if (table->free_entry_list)
--    {
--      new = table->free_entry_list;
--      table->free_entry_list = new->next;
--    }
--  else
--    {
--#if USE_OBSTACK
--      new = obstack_alloc (&table->entry_stack, sizeof *new);
--#else
--      new = malloc (sizeof *new);
--#endif
--    }
--
--  return new;
--}
--
--/* Free a hash entry which was part of some bucket overflow,
--   saving it for later recycling.  */
--
--static void
--free_entry (Hash_table *table, struct hash_entry *entry)
--{
--  entry->data = NULL;
--  entry->next = table->free_entry_list;
--  table->free_entry_list = entry;
--}
--
--/* This private function is used to help with insertion and deletion.  When
--   ENTRY matches an entry in the table, return a pointer to the corresponding
--   user data and set *BUCKET_HEAD to the head of the selected bucket.
--   Otherwise, return NULL.  When DELETE is true and ENTRY matches an entry in
--   the table, unlink the matching entry.  */
--
--static void *
--find_entry (Hash_table *table, const void *entry,
--            struct hash_entry **bucket_head, bool delete)
--{
--  struct hash_entry *bucket = safe_hasher (table, entry);
--
--  *bucket_head = bucket;
--
--  /* Test for empty bucket.  */
--  if (bucket->data == NULL)
--    return NULL;
--
--  /* See if the entry is the first in the bucket.  */
--  if (entry == bucket->data || table->comparator (entry, bucket->data))
--    {
--      void *data = bucket->data;
--
--      if (delete)
--        {
--          if (bucket->next)
--            {
--              struct hash_entry *next = bucket->next;
--
--              /* Bump the first overflow entry into the bucket head, then save
--                 the previous first overflow entry for later recycling.  */
--              *bucket = *next;
--              free_entry (table, next);
--            }
--          else
--            {
--              bucket->data = NULL;
--            }
--        }
--
--      return data;
--    }
--
--  /* Scan the bucket overflow.  */
--  for (struct hash_entry *cursor = bucket; cursor->next; cursor = cursor->next)
--    {
--      if (entry == cursor->next->data
--          || table->comparator (entry, cursor->next->data))
--        {
--          void *data = cursor->next->data;
--
--          if (delete)
--            {
--              struct hash_entry *next = cursor->next;
--
--              /* Unlink the entry to delete, then save the freed entry for later
--                 recycling.  */
--              cursor->next = next->next;
--              free_entry (table, next);
--            }
--
--          return data;
--        }
--    }
--
--  /* No entry found.  */
--  return NULL;
--}
--
--/* Internal helper, to move entries from SRC to DST.  Both tables must
--   share the same free entry list.  If SAFE, only move overflow
--   entries, saving bucket heads for later, so that no allocations will
--   occur.  Return false (setting errno) if the free entry list is
--   exhausted and an allocation fails.  */
--
--static bool
--transfer_entries (Hash_table *dst, Hash_table *src, bool safe)
--{
--  for (struct hash_entry *bucket = src->bucket; bucket < src->bucket_limit; bucket++)
--    if (bucket->data)
--      {
--        void *data;
--        struct hash_entry *new_bucket;
--
--        /* Within each bucket, transfer overflow entries first and
--           then the bucket head, to minimize memory pressure.  After
--           all, the only time we might allocate is when moving the
--           bucket head, but moving overflow entries first may create
--           free entries that can be recycled by the time we finally
--           get to the bucket head.  */
--        for (struct hash_entry *cursor = bucket->next; cursor; )
--          {
--            data = cursor->data;
--            new_bucket = safe_hasher (dst, data);
--
--            struct hash_entry *next = cursor->next;
--
--            if (new_bucket->data)
--              {
--                /* Merely relink an existing entry, when moving from a
--                   bucket overflow into a bucket overflow.  */
--                cursor->next = new_bucket->next;
--                new_bucket->next = cursor;
--              }
--            else
--              {
--                /* Free an existing entry, when moving from a bucket
--                   overflow into a bucket header.  */
--                new_bucket->data = data;
--                dst->n_buckets_used++;
--                free_entry (dst, cursor);
--              }
--
--            cursor = next;
--          }
--        /* Now move the bucket head.  Be sure that if we fail due to
--           allocation failure that the src table is in a consistent
--           state.  */
--        data = bucket->data;
--        bucket->next = NULL;
--        if (!safe)
--          {
--            new_bucket = safe_hasher (dst, data);
--
--            if (new_bucket->data)
--              {
--                /* Allocate or recycle an entry, when moving from a bucket
--                   header into a bucket overflow.  */
--                struct hash_entry *new_entry = allocate_entry (dst);
--
--                if (new_entry == NULL)
--                  return false;
--
--                new_entry->data = data;
--                new_entry->next = new_bucket->next;
--                new_bucket->next = new_entry;
--              }
--            else
--              {
--                /* Move from one bucket header to another.  */
--                new_bucket->data = data;
--                dst->n_buckets_used++;
--              }
--            bucket->data = NULL;
--            src->n_buckets_used--;
--          }
--      }
--  return true;
--}
--
--bool
--hash_rehash (Hash_table *table, size_t candidate)
--{
--  size_t new_size = compute_bucket_size (candidate, table->tuning);
--
--  if (!new_size)
--    return false;
--  if (new_size == table->n_buckets)
--    return true;
--
--  Hash_table storage;
--  Hash_table *new_table = &storage;
--  new_table->bucket = calloc (new_size, sizeof *new_table->bucket);
--  if (new_table->bucket == NULL)
--    return false;
--  new_table->n_buckets = new_size;
--  new_table->bucket_limit = new_table->bucket + new_size;
--  new_table->n_buckets_used = 0;
--  new_table->n_entries = 0;
--  new_table->tuning = table->tuning;
--  new_table->hasher = table->hasher;
--  new_table->comparator = table->comparator;
--  new_table->data_freer = table->data_freer;
--
--  /* In order for the transfer to successfully complete, we need
--     additional overflow entries when distinct buckets in the old
--     table collide into a common bucket in the new table.  The worst
--     case possible is a hasher that gives a good spread with the old
--     size, but returns a constant with the new size; if we were to
--     guarantee table->n_buckets_used-1 free entries in advance, then
--     the transfer would be guaranteed to not allocate memory.
--     However, for large tables, a guarantee of no further allocation
--     introduces a lot of extra memory pressure, all for an unlikely
--     corner case (most rehashes reduce, rather than increase, the
--     number of overflow entries needed).  So, we instead ensure that
--     the transfer process can be reversed if we hit a memory
--     allocation failure mid-transfer.  */
--
--  /* Merely reuse the extra old space into the new table.  */
--#if USE_OBSTACK
--  new_table->entry_stack = table->entry_stack;
--#endif
--  new_table->free_entry_list = table->free_entry_list;
--
--  if (transfer_entries (new_table, table, false))
--    {
--      /* Entries transferred successfully; tie up the loose ends.  */
--      free (table->bucket);
--      table->bucket = new_table->bucket;
--      table->bucket_limit = new_table->bucket_limit;
--      table->n_buckets = new_table->n_buckets;
--      table->n_buckets_used = new_table->n_buckets_used;
--      table->free_entry_list = new_table->free_entry_list;
--      /* table->n_entries and table->entry_stack already hold their value.  */
--      return true;
--    }
--
--  /* We've allocated new_table->bucket (and possibly some entries),
--     exhausted the free list, and moved some but not all entries into
--     new_table.  We must undo the partial move before returning
--     failure.  The only way to get into this situation is if new_table
--     uses fewer buckets than the old table, so we will reclaim some
--     free entries as overflows in the new table are put back into
--     distinct buckets in the old table.
--
--     There are some pathological cases where a single pass through the
--     table requires more intermediate overflow entries than using two
--     passes.  Two passes give worse cache performance and takes
--     longer, but at this point, we're already out of memory, so slow
--     and safe is better than failure.  */
--  int saved_errno = errno;
--  table->free_entry_list = new_table->free_entry_list;
--  if (! (transfer_entries (table, new_table, true)
--         && transfer_entries (table, new_table, false)))
--    abort ();
--  /* table->n_entries already holds its value.  */
--  free (new_table->bucket);
--  errno = saved_errno;
--  return false;
--}
--
--int
--hash_insert_if_absent (Hash_table *table, void const *entry,
--                       void const **matched_ent)
--{
--
--  /* The caller cannot insert a NULL entry, since hash_lookup returns NULL
--     to indicate "not found", and find_entry uses "bucket->data == NULL"
--     to indicate an empty bucket.  */
--  if (! entry)
--    abort ();
--
--  /* If there's a matching entry already in the table, return that.  */
--  struct hash_entry *bucket;
--  void *data = find_entry (table, entry, &bucket, false);
--  if (data != NULL)
--    {
--      if (matched_ent)
--        *matched_ent = data;
--      return 0;
--    }
--
--  /* If the growth threshold of the buckets in use has been reached, increase
--     the table size and rehash.  There's no point in checking the number of
--     entries:  if the hashing function is ill-conditioned, rehashing is not
--     likely to improve it.  */
--
--  if (table->n_buckets_used
--      > table->tuning->growth_threshold * table->n_buckets)
--    {
--      /* Check more fully, before starting real work.  If tuning arguments
--         became invalid, the second check will rely on proper defaults.  */
--      check_tuning (table);
--      if (table->n_buckets_used
--          > table->tuning->growth_threshold * table->n_buckets)
--        {
--          const Hash_tuning *tuning = table->tuning;
--          float candidate =
--            (tuning->is_n_buckets
--             ? (table->n_buckets * tuning->growth_factor)
--             : (table->n_buckets * tuning->growth_factor
--                * tuning->growth_threshold));
--
--          if ((float) SIZE_MAX <= candidate)
--            {
--              errno = ENOMEM;
--              return -1;
--            }
--
--          /* If the rehash fails, arrange to return NULL.  */
--          if (!hash_rehash (table, candidate))
--            return -1;
--
--          /* Update the bucket we are interested in.  */
--          if (find_entry (table, entry, &bucket, false) != NULL)
--            abort ();
--        }
--    }
--
--  /* ENTRY is not matched, it should be inserted.  */
--
--  if (bucket->data)
--    {
--      struct hash_entry *new_entry = allocate_entry (table);
--
--      if (new_entry == NULL)
--        return -1;
--
--      /* Add ENTRY in the overflow of the bucket.  */
--
--      new_entry->data = (void *) entry;
--      new_entry->next = bucket->next;
--      bucket->next = new_entry;
--      table->n_entries++;
--      return 1;
--    }
--
--  /* Add ENTRY right in the bucket head.  */
--
--  bucket->data = (void *) entry;
--  table->n_entries++;
--  table->n_buckets_used++;
--
--  return 1;
--}
--
--void *
--hash_insert (Hash_table *table, void const *entry)
--{
--  void const *matched_ent;
--  int err = hash_insert_if_absent (table, entry, &matched_ent);
--  return (err == -1
--          ? NULL
--          : (void *) (err == 0 ? matched_ent : entry));
--}
--
--void *
--hash_remove (Hash_table *table, const void *entry)
--{
--  struct hash_entry *bucket;
--  void *data = find_entry (table, entry, &bucket, true);
--  if (!data)
--    return NULL;
--
--  table->n_entries--;
--  if (!bucket->data)
--    {
--      table->n_buckets_used--;
--
--      /* If the shrink threshold of the buckets in use has been reached,
--         rehash into a smaller table.  */
--
--      if (table->n_buckets_used
--          < table->tuning->shrink_threshold * table->n_buckets)
--        {
--          /* Check more fully, before starting real work.  If tuning arguments
--             became invalid, the second check will rely on proper defaults.  */
--          check_tuning (table);
--          if (table->n_buckets_used
--              < table->tuning->shrink_threshold * table->n_buckets)
--            {
--              const Hash_tuning *tuning = table->tuning;
--              size_t candidate =
--                (tuning->is_n_buckets
--                 ? table->n_buckets * tuning->shrink_factor
--                 : (table->n_buckets * tuning->shrink_factor
--                    * tuning->growth_threshold));
--
--              if (!hash_rehash (table, candidate))
--                {
--                  /* Failure to allocate memory in an attempt to
--                     shrink the table is not fatal.  But since memory
--                     is low, we can at least be kind and free any
--                     spare entries, rather than keeping them tied up
--                     in the free entry list.  */
--#if ! USE_OBSTACK
--                  struct hash_entry *cursor = table->free_entry_list;
--                  struct hash_entry *next;
--                  while (cursor)
--                    {
--                      next = cursor->next;
--                      free (cursor);
--                      cursor = next;
--                    }
--                  table->free_entry_list = NULL;
--#endif
--                }
--            }
--        }
--    }
--
--  return data;
--}
--
--/* Testing.  */
--
--#if TESTING
--
--void
--hash_print (const Hash_table *table)
--{
--  for (struct hash_entry *bucket = (struct hash_entry *) table->bucket;
--       bucket < table->bucket_limit;
--       bucket++)
--    {
--      if (bucket)
--        printf ("%lu:\n", (unsigned long int) (bucket - table->bucket));
--
--      for (struct hash_entry *cursor = bucket; cursor; cursor = cursor->next)
--        {
--          char const *s = cursor->data;
--          /* FIXME */
--          if (s)
--            printf ("  %s\n", s);
--        }
--    }
--}
--
--#endif /* TESTING */
-diff --git a/misc/next-prime.c b/misc/next-prime.c
-deleted file mode 100644
-index 62fbf94a47caf174..0000000000000000
---- a/misc/next-prime.c
-+++ /dev/null
-@@ -1,64 +0,0 @@
--/* Finding the next prime >= a given small integer.
--   Copyright (C) 1995-2026 Free Software Foundation, Inc.
--
--   This file is free software: you can redistribute it and/or modify
--   it under the terms of the GNU Lesser General Public License as
--   published by the Free Software Foundation; either version 2.1 of the
--   License, or (at your option) any later version.
--
--   This file 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 Lesser General Public License for more details.
--
--   You should have received a copy of the GNU Lesser General Public License
--   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
--
--#include <config.h>
--#ifdef _LIBC
--# include <stdbool.h>
--#endif
--
--/* Specification.  */
--#include "next-prime.h"
--
--#include <stdint.h> /* for SIZE_MAX */
--
--/* Return true if CANDIDATE is a prime number or 1.
--   CANDIDATE should be an odd number >= 1.  */
--static bool _GL_ATTRIBUTE_CONST
--is_prime (size_t candidate)
--{
--  size_t divisor = 3;
--  size_t square = divisor * divisor;
--
--  for (;;)
--    {
--      if (square > candidate)
--        return true;
--      if ((candidate % divisor) == 0)
--        return false;
--      /* Increment divisor by 2.  */
--      divisor++;
--      square += 4 * divisor;
--      divisor++;
--    }
--}
--
--size_t _GL_ATTRIBUTE_CONST
--next_prime (size_t candidate)
--{
--#if !defined IN_LIBGETTEXTLIB
--  /* Skip small primes.  */
--  if (candidate < 10)
--    candidate = 10;
--#endif
--
--  /* Make it definitely odd.  */
--  candidate |= 1;
--
--  while (SIZE_MAX != candidate && !is_prime (candidate))
--    candidate += 2;
--
--  return candidate;
--}
-diff --git a/sysdeps/mach/hurd/opendir.c b/sysdeps/mach/hurd/opendir.c
-index e610236a583d6547..ee005cc37169f41f 100644
---- a/sysdeps/mach/hurd/opendir.c
-+++ b/sysdeps/mach/hurd/opendir.c
-@@ -66,15 +66,14 @@ _hurd_fd_opendir (struct hurd_fd *d)
- 
- 
- DIR *
--__opendirat (int dfd, const char *name, int extra_flags, int *pnew_fd)
-+__opendirat (int dfd, const char *name)
- {
-   if (name[0] == '\0')
-     /* POSIX.1-1990 says an empty name gets ENOENT;
-        but `open' might like it fine.  */
-     return __hurd_fail (ENOENT), NULL;
- 
--  int flags = O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC
--    | extra_flags;
-+  int flags = O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC;
-   int fd;
- #if IS_IN (rtld)
-   assert (dfd == AT_FDCWD);
-@@ -89,8 +88,6 @@ __opendirat (int dfd, const char *name, int extra_flags, int *pnew_fd)
-   DIR *dirp = _hurd_fd_opendir (_hurd_fd_get (fd));
-   if (dirp == NULL)
-     __close (fd);
--  else if (pnew_fd != NULL)
--    *pnew_fd = fd;
- 
-   return dirp;
- }
-diff --git a/sysdeps/unix/sysv/linux/opendir.c b/sysdeps/unix/sysv/linux/opendir.c
-index 9c41a8ff3e78ba57..ceaaefe2bbbd74a7 100644
---- a/sysdeps/unix/sysv/linux/opendir.c
-+++ b/sysdeps/unix/sysv/linux/opendir.c
-@@ -66,24 +66,12 @@ opendir_tail (int fd)
- 
- #if IS_IN (libc)
- DIR *
--__opendirat (int dfd, const char *name, int extra_flags, int *pnew_fd)
-+__opendirat (int dfd, const char *name)
- {
-   if (__glibc_unlikely (invalid_name (name)))
-     return NULL;
- 
--  int open_oflags = opendir_oflags | extra_flags;
--  int new_fd = __openat_nocancel (dfd, name, open_oflags);
--  if (new_fd < 0)
--    return NULL;
--  DIR *dirp = opendir_tail (new_fd);
--  if (dirp == NULL)
--    {
--      __close_nocancel_nostatus (new_fd);
--      return NULL;
--    }
--  else if (pnew_fd != NULL)
--    *pnew_fd = new_fd;
--  return dirp;
-+  return opendir_tail (__openat_nocancel (dfd, name, opendir_oflags));
- }
- #endif
- 
--- 
-2.53.0
-

diff --git a/glibc.spec b/glibc.spec
index 326c809..771c679 100644
--- a/glibc.spec
+++ b/glibc.spec
@@ -1,4 +1,4 @@
-%global glibcsrcdir glibc-2.44.9000-95-g53e5f02a6b
+%global glibcsrcdir glibc-2.44.9000-201-g04a3995650
 %global glibcversion 2.44.9000
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
@@ -152,7 +152,7 @@ Version: %{glibcversion}
 # - It allows using the Release number without the %%dist tag in the dependency
 #   generator to make the generated requires interchangeable between Rawhide
 #   and ELN (.elnYY < .fcXX).
-%global baserelease 2
+%global baserelease 3
 Release: %{baserelease}%{?dist}
 
 # Licenses:
@@ -401,8 +401,6 @@ rpm.define("__debug_install_post bash " .. wrapper
 Patch13: glibc-fedora-localedata-rh61908.patch
 Patch17: glibc-cs-path.patch
 Patch18: glibc-rh2426825.patch
-Patch19: glibc-rh2457183-1.patch
-Patch20: glibc-rh2457183-2.patch
 
 ##############################################################################
 # Continued list of core "glibc" package information:
@@ -2479,6 +2477,119 @@ update_gconv_modules_cache ()
 %endif
 
 %changelog
+* Thu Sep 24 2026 Frédéric Bérat <fberat@redhat.com> - 2.44.9000-3
+- Auto-sync with upstream branch master,
+  commit 04a3995650ec181e98b768fef59f1ad228a87be5:
+- advisories: fix tag for CVE in SA-2026-0023 (Rolf Eike Beer)
+- Update CVSSv3.1 score for GLIBC-SA-2026-0022 (Carlos O'Donell)
+- Publish CVE-2026-95818 advisory (Carlos O'Donell)
+- Publish CVE-2026-86805 advisory (Carlos O'Donell)
+- elf: Fix ld.so SIGSEGV in trace mode with unresolved TLS symbols (BZ 34532) (Adhemerval Zanella)
+- nptl: Retry SIGSETXID delivery on EAGAIN in setxid (bug 21108) (Adhemerval Zanella)
+- math: Sync tgamma with CORE-MATH (Adhemerval Zanella)
+- math: Sync exp10m1f with CORE-MATH (Adhemerval Zanella)
+- math: Sync acosf with CORE-MATH (Adhemerval Zanella)
+- math: Sync lgamma with CORE-MATH (Adhemerval Zanella)
+- Fix d_t_fmt and date_fmt in en_SE [BZ #34635] (Mike FABIAN)
+- stdlib: Don't call clearenv from __libc_setenv_freemem (Mark Wielaard)
+- Publish CVE-2026-8674 advisory (Adhemerval Zanella)
+- malloc: Improve calloc [BZ #34582] (Wilco Dijkstra)
+- x86-64: Link tst-shstk-legacy-1{f,g} with -Wl,--no-as-needed (H.J. Lu)
+- Revert "linux: Add __libc_procmaps_iterate" (Adhemerval Zanella)
+- Revert "linux: Use __libc_procmaps_iterate on __readonly_area_fallback" (Adhemerval Zanella)
+- Revert "nptl: Use __libc_procmaps_iterate on pthread_getattr_np" (Adhemerval Zanella)
+- Revert "nptl: Fall back to AT_EXECFN on __pthread_main_stack without /proc" (Adhemerval Zanella)
+- Revert "nptl: Account for the stack guard gap on pthread_getattr_np (BZ 34637)" (Adhemerval Zanella)
+- Mark swapcontext returns_twice by default [BZ #23130] (Stian Halseth)
+- libio: validate the wide vtable via a bounds-checked index (Alessandro Schino)
+- resolv: Fix assertion failure on search list truncation [BZ 31026, CVE-2026-8674] (Adhemerval Zanella)
+- nptl: Account for the stack guard gap on pthread_getattr_np (BZ 34637) (Adhemerval Zanella)
+- nptl: Fall back to AT_EXECFN on __pthread_main_stack without /proc (Adhemerval Zanella)
+- nptl: Use __libc_procmaps_iterate on pthread_getattr_np (Adhemerval Zanella)
+- linux: Use __libc_procmaps_iterate on __readonly_area_fallback (Adhemerval Zanella)
+- linux: Add __libc_procmaps_iterate (Adhemerval Zanella)
+- linux: Add buffer argument and line truncation to __libc_procutils_read_file (Adhemerval Zanella)
+- Publish CVE-2026-80489 advisory (Carlos O'Donell)
+- Publish CVE-2026-77117 advisory (Carlos O'Donell)
+- Publish CVE-2026-19542 advisory (Adhemerval Zanella)
+- Publish CVE-2026-19499 advisory (Adhemerval Zanella)
+- math: Update tanh from CORE-MATH (revision dbd377a9) (Adhemerval Zanella)
+- io: Reject an empty path list on fts_open [BZ #25434] [BZ #34610] (Adhemerval Zanella)
+- malloc: Reject the top chunk in mem2chunk_check (Magnus Lindholm)
+- aarch64: Add MTE mode tunable (Yury Khrustalev)
+- elf: Do not load cache extensions from an old-format ld.so.cache [BZ #34600] (Shamil Abdulaev)
+- Publish CVE-2026-89092 advisory (Siddhesh Poyarekar)
+- x86: Set AVX10 active only if XMM/YMM/ZMM are supported (H.J. Lu)
+- time: handle ^ and # modifiers with %Z in wcsftime (bug 34611) (Andreas Schwab)
+- x86: Detect APX_NCI_NDD_NF (H.J. Lu)
+- math: let architectures signal underflow after narrowing (Matt Turner)
+- locale: fix memory leaks in write_locales and write_charmaps (Ruslan Valiyev)
+- math: Set errno to ERANGE for logb (+-0) [BZ #6793] (Shamil Abdulaev)
+- alpha: Use a comdat group for the shared divide-by-zero handler [BZ #20543] (Matt Turner)
+- nptl: Skip pretty-printer tests without python3 [BZ #34507] (Hemanth Kumar M D)
+- Record CVE-2026-18374 fix (Florian Weimer)
+- libio: Add test for fopen with an empty ", ccs=" value [BZ #34574] (Shamil Abdulaev)
+- libio: Fix CVE-2026-18374 heap buffer overflow in ccs= handling (Dongkyun Son)
+- getrusage: Add smoke test for getrusage (Ondrej Marek)
+- powerpc: Restore NULL check on _rtld_global_ro in INIT_ARCH [BZ #34503] (Michael Pfeifroth)
+- stdio-common: Skip the a and A conversions for the IBM extended format (Matt Turner)
+- stdio-common: Handle subnormal values in the printf format tests (Matt Turner)
+- stdio-common: Add printf format tests for the a and A conversions (Matt Turner)
+- stdio-common: Add printf format tests for the b and B conversions (Matt Turner)
+- stdio-common: Verify printf format tests with Python rather than AWK (Matt Turner)
+- hurd: Make __file_name_lookup_at apply upmask for O_TMPFILE (BZ 34493) (Samuel Thibault)
+- hurd: Make readlinkat check bogus length returned by translator (BZ 34504) (Samuel Thibault)
+- hurd: Fix setreuid/setregid setting saved ID to new effective ID (BZ 34505) (Samuel Thibault)
+- stdlib, wcsmbs: Add missing __nonnull to strto*/wcsto* [BZ #33053] (Shamil Abdulaev)
+- elf: Open the normalized $ORIGIN rpath in AT_SECURE programs (BZ 34360) (Adhemerval Zanella)
+- test: Fix tst-personality (Yury Khrustalev)
+- manual: adjust reference to man-pages following proc(5) split-up (Collin Funk)
+- Updates udp.h from Linux 6.19 to netinet/udp.h (Jiayuan Chen)
+- nptl: Test case for bug 34546 (Florian Weimer)
+- nptl: Use FAIL_UNSUPPORTED in init_tpp_test in tst-tpp.h (Florian Weimer)
+- nptl: Revert TPP updates on pthread_mutex_*lock failure (bug 34546) (Florian Weimer)
+- nptl: Fix test error reporting in CHECK_TPP_PRIORITY in tst-tpp.h (Florian Weimer)
+- nptl: Revert robust list head on pthread_mutex_timedlock failure (bug 34542) (Florian Weimer)
+- nptl: Treat negative times as timed out in PI futex locking (bug 34543) (Florian Weimer)
+- stdio-common: Keep trailing zeros where %#g rounds into a new decade (BZ 34578) (Matt Turner)
+- stdio-common: Iterate over the huge width for one printf function only (Matt Turner)
+- elf: Remove dead l_need_tls_init static-TLS init path (Adhemerval Zanella)
+- elf: Remove __chk_fail from dl-minimal.c (Adhemerval Zanella)
+- elf: Allow RPATH/RUNPATH for static-pie (BZ 33326) (Adhemerval Zanella)
+- Fix assert during static startup (BZ 33326) (Adhemerval Zanella)
+- Use _dl_writev on __libc_message_impl (Adhemerval Zanella)
+- nptl: Add __raise_direct (Adhemerval Zanella)
+- tst-backtrace5: split long line (Samuel Thibault)
+- tst-backtrace5: Fix on hurd (Samuel Thibault)
+- fcntl: drop nonnull attribute for openat, openat2's path argument [BZ #34313] (Sam James)
+- io: drop nonnull attribute for fchmodat, faccessat, fchownat's path argument [BZ #34313] (Sam James)
+- hurd: Move SINGLE_THREAD_P / RTLD_SINGLE_THREAD_P to single-thread.h (Samuel Thibault)
+- stdlib: merge some tests from gnulib (Collin Funk)
+- nptl: Propagate EDEADLK from FUTEX_LOCK_PI for errror-checking mutexes (Moritz Klammler)
+- advisories: fix typo in README (Rolf Eike Beer)
+- Use __attribute_optimization_barrier__ for the remaining noclone users (Matt Turner)
+- io: Do not alias fts and fts64 when inode types differ (Magnus Lindholm)
+- Use FAIL_UNSUPPORTED more (Sam James)
+- iconvdata: Test case for bug 34556, bug 34568 (Florian Weimer)
+- iconvdata: EUC_JISX0213 decoding lacks pending character reset (CVE-2026-80489) (Florian Weimer)
+- iconvdata: SHIFT_JISX0213 decoding lacks pending character reset (CVE-2026-77117) (Florian Weimer)
+- localedata: bn_BD, bn_IN: use full Gregorian month names for abmon (Azharul Haque)
+- manual: Fix some typos in the Low-Level Input/Output chapter (Collin Funk)
+- x86: Update AVX10 support (H.J. Lu)
+- Document CVE-2026-18374 and new CVSS tag (Siddhesh Poyarekar)
+- aarch64: Add memory clobber to pkey_write (Yury Khrustalev)
+- stdlib: Fix right-justification in strfmon (bug 34510, CVE-2026-19499) (Florian Weimer)
+- hurd: Set _TIME_BITS=32 for installed programs on i386/Hurd (Samuel Thibault)
+- Add check-symbol-version.awk (H.J. Lu)
+- LoongArch: Add standard search paths for 32-bit (mengqinggang)
+- LoongArch: Support pointer guard on LoongArch32 (mengqinggang)
+- hurd: Warn about setting _TIME_BITS=64 on i386 GNU Hurd (Samuel Thibault)
+- math: Update tanh from CORE-MATH (revision bb39e4fa) (Adhemerval Zanella)
+- tests: elf: Fix flaky thp tests (Yury Khrustalev)
+- Remove applied or redundant patches:
+  - glibc-rh2457183-1.patch
+  - glibc-rh2457183-2.patch
+
 * Tue Sep 01 2026 Florian Weimer  <fweimer@redhat.com> - 2.44.9000-2
 - Fail the build if there are unexpected test failures (#2449608)
 

diff --git a/sources b/sources
index 0a5e87d..e31878f 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (glibc-2.44.9000-95-g53e5f02a6b.tar.xz) = b6fa43c7f372cd7efa813880b7619818e1fb5102a0bf7dc879f4d60be9d1e9e1abca4f42ecb709902329ca8b0ac0a8e076d89f7bb2ea771d6861eb0d541c582d
+SHA512 (glibc-2.44.9000-201-g04a3995650.tar.xz) = bb4d25275c6071be9a0163500bb78e27ea103fa8704660f51815d3d1e1b0dd98f80d6920c751b732d7ed0a7a0842668a75ccebb0e37703a17a3b8071957e1b16

^ permalink raw reply related	[flat|nested] 7+ messages in thread
* [rpms/glibc] rawhide: Auto-sync with upstream branch master
@ 2026-07-21 17:07 
  0 siblings, 0 replies; 7+ messages in thread
From:  @ 2026-07-21 17:07 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/glibc
            Branch : rawhide
            Commit : 6c96db62b78890597487a9386e1a2d3358148332
            Author : Frédéric Bérat <fberat@redhat.com>
            Date   : 2026-07-21T11:12:47+02:00
            Stats  : +47/-3 in 2 file(s)
            URL    : https://src.fedoraproject.org/rpms/glibc/c/6c96db62b78890597487a9386e1a2d3358148332?branch=rawhide

            Log:
            Auto-sync with upstream branch master

Upstream commit: a5aa0df24ad61a7dbc0f7c0dc9da7387ec0e974d

- hurd: demangle pointers on fork's longjmp (Samuel Thibault)
- hurd: Add __readlink and readlink to dl-sysdep.c (Samuel Thibault)
- hurd: Add __fstatat64 to dl-sysdep.c (Samuel Thibault)
- manual: Add stability warning regarding system-wide tunables (Florian Weimer)
- contrib.texi: update (Andreas K. Hüttel)
- NEWS: insert list of fixed bugs (Andreas K. Hüttel)
- NEWS: editorial changes (Andreas K. Hüttel)
- math: Update tanh from CORE-MATH (revision cf237fa0) (Adhemerval Zanella)
- Revert "malloc: Remove dynamic mmap/trim threshold [BZ #30769]" (Peter Bergner)
- Add RWF_NOSIGNAL from Linux 6.18 to bits/uio-ext.h (Adhemerval Zanella)
- math: Fix inaccurate sin/cos/tan for large arguments (BZ 34376) (Adhemerval Zanella)
- benchtests: Add path-oriented workloads to tan (Adhemerval Zanella)
- benchtests: Add path-oriented workloads to sin (Adhemerval Zanella)
- benchtests: Add path-oriented workloads to cos (Adhemerval Zanella)
- sparc: Align THP tests to the 8MB huge-page size (Adhemerval Zanella)
- elf: Defer arch PLT IFUNC relocations in the two-phase relocation split (Adhemerval Zanella)
- sparc: Fix static IFUNC startup crash by redirecting __mempcpy (BZ #34396) (Adhemerval Zanella)
- Revert "strace-tst-thp.sh: Allow unsupported THP tests" (H.J. Lu)
- strace-tst-thp.sh: Allow unsupported THP tests (H.J. Lu)
- thp: Disable THP if THP isn't supported by kernel (H.J. Lu)
- thp: Link THP PDE tests with $(LOAD-THP-ADDRESS-LDFLAGS) (H.J. Lu)
- Add advisory text for CVE-2026-6368 (Adhemerval Zanella)
- posix: Fix wordexp WRDE_APPEND to preserve state on non-NOSPACE errors (BZ 34090, CVE-2026-6368) (Adhemerval Zanella)
- ldconfig: add --install option (DJ Delorie)
- po: Integrate translations (Andreas K. Hüttel)
- s390: Use 64bit branch relative on count instruction in strncpy-z900.S [BZ #34398] (Stefan Liebler)
- Use correct type for glibc.malloc.perturb in tst-tunconf1.c (Stefan Liebler)
- benchtests: Build benchmarks in parallel (Adhemerval Zanella)
- sparc: Fix static (non-PIE) executables when PIE is enabled by default (Adhemerval Zanella)
- elf: Remove unused tunable_seclevel_t (Adhemerval Zanella)
- elf: Remove _dl_unload_cache (Adhemerval Zanella)
- manual: Document default AT_SECURE handling for system-wide tunables (Adhemerval Zanella)
- elf: Let environment aliases override overridable system-wide tunables (Adhemerval Zanella)
- elf: Avoid redundant ld.so.cache reload after first load (Adhemerval Zanella)
- elf: Verify the tunable cache header signature and version (Adhemerval Zanella)
- elf: Bound the tunable cache string table against the mapping size (Adhemerval Zanella)
- localedata: Use libc-alpha ML as the canonical contact (Siddhesh Poyarekar)
- posix: Use unique PID file in tst-spawn3 and tst-spawn3-pidfd (Florian Weimer)
- localedata: Avoid concurrently written locales in gen-locale.sh (Florian Weimer)
- Add system-wide tunables: implement overridability (DJ Delorie)

---
diff --git a/glibc.spec b/glibc.spec
index bcbfc01..2bbd944 100644
--- a/glibc.spec
+++ b/glibc.spec
@@ -1,4 +1,4 @@
-%global glibcsrcdir glibc-2.43.9000-496-gb5eecf35d9
+%global glibcsrcdir glibc-2.43.9000-536-ga5aa0df24a
 %global glibcversion 2.43.9000
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
@@ -152,7 +152,7 @@ Version: %{glibcversion}
 # - It allows using the Release number without the %%dist tag in the dependency
 #   generator to make the generated requires interchangeable between Rawhide
 #   and ELN (.elnYY < .fcXX).
-%global baserelease 24
+%global baserelease 25
 Release: %{baserelease}%{?dist}
 
 # Licenses:
@@ -2404,6 +2404,50 @@ update_gconv_modules_cache ()
 %endif
 
 %changelog
+* Tue Jul 21 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-25
+- Auto-sync with upstream branch master,
+  commit a5aa0df24ad61a7dbc0f7c0dc9da7387ec0e974d:
+- hurd: demangle pointers on fork's longjmp (Samuel Thibault)
+- hurd: Add __readlink and readlink to dl-sysdep.c (Samuel Thibault)
+- hurd: Add __fstatat64 to dl-sysdep.c (Samuel Thibault)
+- manual: Add stability warning regarding system-wide tunables (Florian Weimer)
+- contrib.texi: update (Andreas K. Hüttel)
+- NEWS: insert list of fixed bugs (Andreas K. Hüttel)
+- NEWS: editorial changes (Andreas K. Hüttel)
+- math: Update tanh from CORE-MATH (revision cf237fa0) (Adhemerval Zanella)
+- Revert "malloc: Remove dynamic mmap/trim threshold [BZ #30769]" (Peter Bergner)
+- Add RWF_NOSIGNAL from Linux 6.18 to bits/uio-ext.h (Adhemerval Zanella)
+- math: Fix inaccurate sin/cos/tan for large arguments (BZ 34376) (Adhemerval Zanella)
+- benchtests: Add path-oriented workloads to tan (Adhemerval Zanella)
+- benchtests: Add path-oriented workloads to sin (Adhemerval Zanella)
+- benchtests: Add path-oriented workloads to cos (Adhemerval Zanella)
+- sparc: Align THP tests to the 8MB huge-page size (Adhemerval Zanella)
+- elf: Defer arch PLT IFUNC relocations in the two-phase relocation split (Adhemerval Zanella)
+- sparc: Fix static IFUNC startup crash by redirecting __mempcpy (BZ #34396) (Adhemerval Zanella)
+- Revert "strace-tst-thp.sh: Allow unsupported THP tests" (H.J. Lu)
+- strace-tst-thp.sh: Allow unsupported THP tests (H.J. Lu)
+- thp: Disable THP if THP isn't supported by kernel (H.J. Lu)
+- thp: Link THP PDE tests with $(LOAD-THP-ADDRESS-LDFLAGS) (H.J. Lu)
+- Add advisory text for CVE-2026-6368 (Adhemerval Zanella)
+- posix: Fix wordexp WRDE_APPEND to preserve state on non-NOSPACE errors (BZ 34090, CVE-2026-6368) (Adhemerval Zanella)
+- ldconfig: add --install option (DJ Delorie)
+- po: Integrate translations (Andreas K. Hüttel)
+- s390: Use 64bit branch relative on count instruction in strncpy-z900.S [BZ #34398] (Stefan Liebler)
+- Use correct type for glibc.malloc.perturb in tst-tunconf1.c (Stefan Liebler)
+- benchtests: Build benchmarks in parallel (Adhemerval Zanella)
+- sparc: Fix static (non-PIE) executables when PIE is enabled by default (Adhemerval Zanella)
+- elf: Remove unused tunable_seclevel_t (Adhemerval Zanella)
+- elf: Remove _dl_unload_cache (Adhemerval Zanella)
+- manual: Document default AT_SECURE handling for system-wide tunables (Adhemerval Zanella)
+- elf: Let environment aliases override overridable system-wide tunables (Adhemerval Zanella)
+- elf: Avoid redundant ld.so.cache reload after first load (Adhemerval Zanella)
+- elf: Verify the tunable cache header signature and version (Adhemerval Zanella)
+- elf: Bound the tunable cache string table against the mapping size (Adhemerval Zanella)
+- localedata: Use libc-alpha ML as the canonical contact (Siddhesh Poyarekar)
+- posix: Use unique PID file in tst-spawn3 and tst-spawn3-pidfd (Florian Weimer)
+- localedata: Avoid concurrently written locales in gen-locale.sh (Florian Weimer)
+- Add system-wide tunables: implement overridability (DJ Delorie)
+
 * Thu Jul 16 2026 Fedora Release Engineering <releng@fedoraproject.org> - 2.43.9000-24
 - Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild
 

diff --git a/sources b/sources
index 66adb21..c088735 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (glibc-2.43.9000-496-gb5eecf35d9.tar.xz) = c1c40086bcc40e2fb3be338aa0f1f2dd6bfd78010607679b5452cc66f7fbcfddae67d89ba64c23de88fd61d50e917c031ed44d821c6b1bb685f99fc2d2ea8d64
+SHA512 (glibc-2.43.9000-536-ga5aa0df24a.tar.xz) = 79224e8c03fd393a642cd0f5a0b04569f77cb6c01d922e7005ae7d68e8986904a55f00a377c6f6392501e6daba2d4b4f5369b02d433849fdefac5afa9b71086e

^ permalink raw reply related	[flat|nested] 7+ messages in thread
* [rpms/glibc] rawhide: Auto-sync with upstream branch master
@ 2026-07-07 13:52 
  0 siblings, 0 replies; 7+ messages in thread
From:  @ 2026-07-07 13:52 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/glibc
            Branch : rawhide
            Commit : 1f72a54182ed0261b3441c955bfcb2715283ee63
            Author : Frédéric Bérat <fberat@redhat.com>
            Date   : 2026-07-07T09:43:03+02:00
            Stats  : +59/-3 in 2 file(s)
            URL    : https://src.fedoraproject.org/rpms/glibc/c/1f72a54182ed0261b3441c955bfcb2715283ee63?branch=rawhide

            Log:
            Auto-sync with upstream branch master

Upstream commit: b5eecf35d91a3b29cff80b731bbc6bcce6863827

- libc.pot: regenerate (Andreas K. Hüttel)
- Revert "malloc: aarch64: Add ifuncs for malloc functions" (Yury Khrustalev)
- netinet/tcp.h: Sync with Linux 6.15 and fix struct tcp_info tail (BZ 34347) (Adhemerval Zanella)
- Add OPEN_TREE_NAMESPACE and FSMOUNT_NAMESPACE to sys/mount.h (Adhemerval Zanella)
- s390: Prevent hoisting the thread-pointer read in THREAD_SET_STACK_GUARD (BZ 34297) (Adhemerval Zanella)
- Add new AArch64 HWCAP definitions from Linux 6.14, 6.18 and 7.0 to bits/hwcap.h (Adhemerval Zanella)
- Makefile: Depend on elf/subdir_lib only if $(subdirs) has elf (H.J. Lu)
- sysdeps/x86: don't spuriously mark tests as xfail (Andreas Schwab)
- riscv: Add RVV strncpy for both multiarch and non-multiarch builds (Yao Zihong)
- riscv: Add RVV stpncpy for both multiarch and non-multiarch builds (Yao Zihong)
- Add tst-thp-size-mod.so dependency to strace THP tests (H.J. Lu)
- build-many-glibcs.py: Update Linux kernel version to 7.1 (Adhemerval Zanella)
- Update kernel version to 7.1 in header constant tests (Adhemerval Zanella)
- Update syscall lists for Linux 7.1 (Adhemerval Zanella)
- Add NT_RISCV_USER_CFI from Linux 7.0 to elf.h (Adhemerval Zanella)
- Add IPPROTO_AGGFRAG from Linux 6.14 to netinet/in.h (BZ 34347) (Adhemerval Zanella)
- Add SCHED_GETATTR_FLAG_DL_DYNAMIC from Linux 7.1 to bits/sched.h (Adhemerval Zanella)
- Update PIDFD_* constants for Linux 7.1 (Adhemerval Zanella)
- Add new LoongArch HWCAP definitions from Linux 7.0 and 7.1 to bits/hwcap.h (Adhemerval Zanella)
- Add new constants from Linux 6.12, 6.18 and 6.19 to bits/fcntl-linux.h (Adhemerval Zanella)
- x86: Remove unused VZEROUPPER_SHORT_RETURN macro from memset (RyotaSaito)
- string: Fix memory leak in argz-addsep.c (Samuel Balazi)
- Makerules: run test-container helper through the built loader (Adhemerval Zanella)
- Makerules: add 'make check-parallel' to run tests without serialization (Adhemerval Zanella)
- Run check-installed-headers concurrently for each header (Adhemerval Zanella)
- Makefile: Do not install the container testroot if not running tests (Adhemerval Zanella)
- Makefile: Do not force elf last for the others and tests passes (Adhemerval Zanella)
- Makefile: Run the subdirectory recursion in parallel (Adhemerval Zanella)
- scripts/gen-sorted.awk: Also emit the subdirectory dependency edges (Adhemerval Zanella)
- intl: create correct directory in tst-translit.sh (Sam James)
- po/*.po: integrate current state of translations (Andreas K. Hüttel)
- po/libc.pot: regenerate (Andreas K. Hüttel)
- Add system-wide tunables: manual (DJ Delorie)
- Add system-wide tunables: Filters (DJ Delorie)
- Add system-wide tunables: Apply tunables part (DJ Delorie)
- Add system-wide tunables: cache ld.so.cache (DJ Delorie)
- Add system-wide tunables: ldconfig part (DJ Delorie)
- malloc: Don't call __get_thp_mode/__get_thp_size twice (H.J. Lu)
- nis: Fix a memory leak in nis_creategroup when malloc fails (Jiri Stransky)
- stdio-common: Fix scanf nan/inf pushback [BZ #34208] (Xiang Gao)
- nss: Remove --enable-static-nss configure option (Michael Ford)
- manual: Document indirect functions (IFUNC) (Adhemerval Zanella)
- ppc64le: Restore optimized memchr for power10 [BZ #34300] (Sachin Monga)
- riscv: Fix RV32 libthread_db THREAD_SELF register layout (Shengwen Cheng)
- elf: Fix clang-18 build of ifunc resolver tests (Adhemerval Zanella)
- arm: Xfail 2 static THP tests (H.J. Lu)
- thp: Limit THP code padding to 2 * THP page size (H.J. Lu)
- Update documentation of iconv [BZ #30136] (Mike FABIAN)
- AArch64: additional mathvec build system cleanups. (Pierre Blanchard)
- AArch64: Update SHARED-FILES with files from Arm Optimized-Routines (Pierre Blanchard)
- AArch64: Update mathvec directory structure. (Pierre Blanchard)
- hppa: Fix missing call to __feraiseexcept (BZ 34306) (John David Anglin)

---
diff --git a/glibc.spec b/glibc.spec
index d32d4ea..7cb70ae 100644
--- a/glibc.spec
+++ b/glibc.spec
@@ -1,4 +1,4 @@
-%global glibcsrcdir glibc-2.43.9000-444-gb61b98e3d0
+%global glibcsrcdir glibc-2.43.9000-496-gb5eecf35d9
 %global glibcversion 2.43.9000
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
@@ -152,7 +152,7 @@ Version: %{glibcversion}
 # - It allows using the Release number without the %%dist tag in the dependency
 #   generator to make the generated requires interchangeable between Rawhide
 #   and ELN (.elnYY < .fcXX).
-%global baserelease 22
+%global baserelease 23
 Release: %{baserelease}%{?dist}
 
 # Licenses:
@@ -2404,6 +2404,62 @@ update_gconv_modules_cache ()
 %endif
 
 %changelog
+* Tue Jul 07 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-23
+- Auto-sync with upstream branch master,
+  commit b5eecf35d91a3b29cff80b731bbc6bcce6863827:
+- libc.pot: regenerate (Andreas K. Hüttel)
+- Revert "malloc: aarch64: Add ifuncs for malloc functions" (Yury Khrustalev)
+- netinet/tcp.h: Sync with Linux 6.15 and fix struct tcp_info tail (BZ 34347) (Adhemerval Zanella)
+- Add OPEN_TREE_NAMESPACE and FSMOUNT_NAMESPACE to sys/mount.h (Adhemerval Zanella)
+- s390: Prevent hoisting the thread-pointer read in THREAD_SET_STACK_GUARD (BZ 34297) (Adhemerval Zanella)
+- Add new AArch64 HWCAP definitions from Linux 6.14, 6.18 and 7.0 to bits/hwcap.h (Adhemerval Zanella)
+- Makefile: Depend on elf/subdir_lib only if $(subdirs) has elf (H.J. Lu)
+- sysdeps/x86: don't spuriously mark tests as xfail (Andreas Schwab)
+- riscv: Add RVV strncpy for both multiarch and non-multiarch builds (Yao Zihong)
+- riscv: Add RVV stpncpy for both multiarch and non-multiarch builds (Yao Zihong)
+- Add tst-thp-size-mod.so dependency to strace THP tests (H.J. Lu)
+- build-many-glibcs.py: Update Linux kernel version to 7.1 (Adhemerval Zanella)
+- Update kernel version to 7.1 in header constant tests (Adhemerval Zanella)
+- Update syscall lists for Linux 7.1 (Adhemerval Zanella)
+- Add NT_RISCV_USER_CFI from Linux 7.0 to elf.h (Adhemerval Zanella)
+- Add IPPROTO_AGGFRAG from Linux 6.14 to netinet/in.h (BZ 34347) (Adhemerval Zanella)
+- Add SCHED_GETATTR_FLAG_DL_DYNAMIC from Linux 7.1 to bits/sched.h (Adhemerval Zanella)
+- Update PIDFD_* constants for Linux 7.1 (Adhemerval Zanella)
+- Add new LoongArch HWCAP definitions from Linux 7.0 and 7.1 to bits/hwcap.h (Adhemerval Zanella)
+- Add new constants from Linux 6.12, 6.18 and 6.19 to bits/fcntl-linux.h (Adhemerval Zanella)
+- x86: Remove unused VZEROUPPER_SHORT_RETURN macro from memset (RyotaSaito)
+- string: Fix memory leak in argz-addsep.c (Samuel Balazi)
+- Makerules: run test-container helper through the built loader (Adhemerval Zanella)
+- Makerules: add 'make check-parallel' to run tests without serialization (Adhemerval Zanella)
+- Run check-installed-headers concurrently for each header (Adhemerval Zanella)
+- Makefile: Do not install the container testroot if not running tests (Adhemerval Zanella)
+- Makefile: Do not force elf last for the others and tests passes (Adhemerval Zanella)
+- Makefile: Run the subdirectory recursion in parallel (Adhemerval Zanella)
+- scripts/gen-sorted.awk: Also emit the subdirectory dependency edges (Adhemerval Zanella)
+- intl: create correct directory in tst-translit.sh (Sam James)
+- po/*.po: integrate current state of translations (Andreas K. Hüttel)
+- po/libc.pot: regenerate (Andreas K. Hüttel)
+- Add system-wide tunables: manual (DJ Delorie)
+- Add system-wide tunables: Filters (DJ Delorie)
+- Add system-wide tunables: Apply tunables part (DJ Delorie)
+- Add system-wide tunables: cache ld.so.cache (DJ Delorie)
+- Add system-wide tunables: ldconfig part (DJ Delorie)
+- malloc: Don't call __get_thp_mode/__get_thp_size twice (H.J. Lu)
+- nis: Fix a memory leak in nis_creategroup when malloc fails (Jiri Stransky)
+- stdio-common: Fix scanf nan/inf pushback [BZ #34208] (Xiang Gao)
+- nss: Remove --enable-static-nss configure option (Michael Ford)
+- manual: Document indirect functions (IFUNC) (Adhemerval Zanella)
+- ppc64le: Restore optimized memchr for power10 [BZ #34300] (Sachin Monga)
+- riscv: Fix RV32 libthread_db THREAD_SELF register layout (Shengwen Cheng)
+- elf: Fix clang-18 build of ifunc resolver tests (Adhemerval Zanella)
+- arm: Xfail 2 static THP tests (H.J. Lu)
+- thp: Limit THP code padding to 2 * THP page size (H.J. Lu)
+- Update documentation of iconv [BZ #30136] (Mike FABIAN)
+- AArch64: additional mathvec build system cleanups. (Pierre Blanchard)
+- AArch64: Update SHARED-FILES with files from Arm Optimized-Routines (Pierre Blanchard)
+- AArch64: Update mathvec directory structure. (Pierre Blanchard)
+- hppa: Fix missing call to __feraiseexcept (BZ 34306) (John David Anglin)
+
 * Tue Jun 23 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-22
 - Auto-sync with upstream branch master,
   commit b61b98e3d0c81c85200e2082407708c7b0e821a3:

diff --git a/sources b/sources
index 40a3a6b..66adb21 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (glibc-2.43.9000-444-gb61b98e3d0.tar.xz) = debf5148d5fc79bc60897fbed69d68df1d82d006be520970f613b35512c390a4589b2dd684568ac4cd63f9bab109feada68463a8b4f580a16f8c5f330562060f
+SHA512 (glibc-2.43.9000-496-gb5eecf35d9.tar.xz) = c1c40086bcc40e2fb3be338aa0f1f2dd6bfd78010607679b5452cc66f7fbcfddae67d89ba64c23de88fd61d50e917c031ed44d821c6b1bb685f99fc2d2ea8d64

^ permalink raw reply related	[flat|nested] 7+ messages in thread
* [rpms/glibc] rawhide: Auto-sync with upstream branch master
@ 2026-06-23 17:32 
  0 siblings, 0 replies; 7+ messages in thread
From:  @ 2026-06-23 17:32 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/glibc
            Branch : rawhide
            Commit : 93edd35f0767e19ce3801dc8eaa89a00fd7ce518
            Author : Frédéric Bérat <fberat@redhat.com>
            Date   : 2026-06-23T10:37:31+02:00
            Stats  : +48/-591 in 7 file(s)
            URL    : https://src.fedoraproject.org/rpms/glibc/c/93edd35f0767e19ce3801dc8eaa89a00fd7ce518?branch=rawhide

            Log:
            Auto-sync with upstream branch master

Upstream commit: b61b98e3d0c81c85200e2082407708c7b0e821a3

- resolv: Add test for gethostbyname_r unaligned buffer [BZ #18287] (Sergey Kolosov)
- Define _PATH_MOUNTED as "/etc/mtab" (Justus Winter)
- Add advisory text for CVE-2026-6791 (Adhemerval Zanella)
- posix: Fix stack overflow in wordexp tilde expansion (BZ 34091, CVE-2026-6791) (Adhemerval Zanella)
- riscv: Add RVV memmove for both multiarch and non-multiarch builds (Yao Zihong)
- elf: Support THP segment load with madvise enabled THP (H.J. Lu)
- advisories: Update GLIBC-SA-2026-0012 metadata (Carlos O'Donell)
- Remove unused THREAD_SET_POINTER_GUARD and THREAD_COPY_POINTER_GUARD (Adhemerval Zanella)
- resolv: Add test case tst-ns_sprintrr (bug 34033, bug 34069) (Florian Weimer)
- resolv: Fix buffer overreads in ns_sprintrrf (CVE-2026-6238) (Florian Weimer)
- resolv: More types as unknown in ns_sprintrrf (CVE-2026-5435) (Florian Weimer)
- resolv: Check for inet_ntop failure in ns_sprintrrf (Florian Weimer)
- resolv: Improve formatting of unknown records in ns_sprintrrf (Florian Weimer)
- resolv: Fix ns_sprintrrf formatting of class, type values (bug 34289) (Florian Weimer)
- resolv: Declare __p_class_syms, __p_type_syms for internal use (Florian Weimer)
- Update GLIBC-SA-2026-0012 to mention A6 records (Florian Weimer)
- string: Improve memchr random test (Wilco Dijkstra)
- AArch64: Vectorise SVE fp64 sin/cos special case (Dylan Fleming)
- AArch64: Vectorise AdvSIMD fp64 sin/cos special case (Dylan Fleming)
- AArch64: Vectorise SVE fp32 sin/cos special case (Dylan Fleming)
- AArch64: Vectorise AdvSIMD fp32 sin/cos special case (Dylan Fleming)
- news: Describe AArch64-specific changes for 2.44 (Yury Khrustalev)
- elf: Do not scrub AT_RANDOM to a constant when reseeding fails (BZ 34197) (Adhemerval Zanella)
- manual: Update memchr description [BZ #19406] (Wilco Dijkstra)
- hurd: Add ETH_TLEN and ETH_FCS_LEN (Samuel Thibault)
- hurd: Fix ETH_P_PUP (Samuel Thibault)
- Factorize if_arp.h (Samuel Thibault)
- elf: Scrub and reseed the AT_RANDOM bytes after deriving the guards (BZ 34197) (Adhemerval Zanella)
- Consolidate dl-osinfo.h into the generic implementation (Adhemerval Zanella)
- Consolidate the C pointer guard and align the assembly implementations (Adhemerval Zanella)
- Remove the jmp_buf stack pointer demangle on ABIs that do not mangle it (Adhemerval Zanella)
- Split pointer_guard.h into C and assembly headers (Adhemerval Zanella)
- Enable the pointer guard in the dynamic loader (Adhemerval Zanella)
- Consolidate pointer guard to use a relro variable instead of the TCB (Adhemerval Zanella)
- elf: Propagate the pointer guard to ld.so loaded via static dlopen (BZ 34196) (Adhemerval Zanella)

Remove patches already applied upstream:
- glibc-RHEL-172425-1.patch
- glibc-RHEL-172425-2.patch
- glibc-RHEL-172425-3.patch
- glibc-RHEL-172425-4.patch
- glibc-RHEL-172425-5.patch

---
diff --git a/glibc-RHEL-172425-1.patch b/glibc-RHEL-172425-1.patch
deleted file mode 100644
index f2d6383..0000000
--- a/glibc-RHEL-172425-1.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-Taken from: <https://inbox.sourceware.org/libc-alpha/cover.1777546194.git.fweimer@redhat.com/>
-
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Thu Apr 30 12:51:58 2026 +0200
-
-    Update GLIBC-SA-2026-0012 to mention A6 records
-    
-    It turns out there is a missing inner length check in it, too.
-    
-    Also fix the vulnerable commit.  It predates the glibc 2.0 release
-    because the old stream-based formatting code in resolv/res_debug.c had
-    the same bug in its LOC handling.
-
-diff --git a/advisories/GLIBC-SA-2026-0012 b/advisories/GLIBC-SA-2026-0012
-index 6f8f00ddd7b267c4..926ca161028ccfc7 100644
---- a/advisories/GLIBC-SA-2026-0012
-+++ b/advisories/GLIBC-SA-2026-0012
-@@ -2,7 +2,7 @@ Buffer overread in ns_printrrf with corrupted RDATA field
- 
- The deprecated functions ns_printrrf, ns_printrr and fp_nquery in the
- GNU C Library version 2.2 and newer fail to validate the RDATA content
--against the RDATA length in a DNS response when processing LOC, CERT,
-+against the RDATA length in a DNS response when processing A6, CERT, LOC,
- TKEY or TSIG records, which may allow an attacker to craft a DNS
- response, causing a target application to crash or read uninitialized
- memory.
-@@ -15,4 +15,4 @@ interfaces since they may be removed in future versions.
- 
- CVE-Id: CVE-2026-6238
- Public-Date: 2026-04-11
--Vulnerable-Commit: b43b13ac2544b11f35be301d1589b51a8473e32b (2.2)
-+Vulnerable-Commit: ee188d555b8c32ad9704a7440cab400af967292f (1.90)

diff --git a/glibc-RHEL-172425-2.patch b/glibc-RHEL-172425-2.patch
deleted file mode 100644
index 0cb2695..0000000
--- a/glibc-RHEL-172425-2.patch
+++ /dev/null
@@ -1,61 +0,0 @@
-Taken from: <https://inbox.sourceware.org/libc-alpha/cover.1777546194.git.fweimer@redhat.com/>
-
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Thu Apr 30 12:52:02 2026 +0200
-
-    resolv: Check for inet_ntop failure in ns_sprintrrf
-    
-    This makes the output more consistent (either failure or complete
-    output) and helps with systematic testing with varying buffer
-    sizes.
-
-diff --git a/resolv/ns_print.c b/resolv/ns_print.c
-index cef2212fd24b772b..5701e3d0c59f79f1 100644
---- a/resolv/ns_print.c
-+++ b/resolv/ns_print.c
-@@ -141,7 +141,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
- 	case ns_t_a:
- 	  if (rdlen != (size_t)NS_INADDRSZ)
- 			goto formerr;
--		(void) inet_ntop(AF_INET, rdata, buf, buflen);
-+		if (inet_ntop (AF_INET, rdata, buf, buflen) == NULL)
-+		  return -1;
- 		addlen(strlen(buf), &buf, &buflen);
- 		break;
- 
-@@ -308,10 +309,11 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
- 
- 	case ns_t_aaaa:
- 	  if (rdlen != (size_t)NS_IN6ADDRSZ)
--			goto formerr;
--		(void) inet_ntop(AF_INET6, rdata, buf, buflen);
--		addlen(strlen(buf), &buf, &buflen);
--		break;
-+	    goto formerr;
-+	  if (inet_ntop (AF_INET6, rdata, buf, buflen) == NULL)
-+	    return -1;
-+	  addlen(strlen(buf), &buf, &buflen);
-+	  break;
- 
- 	case ns_t_loc: {
- 		char t[255];
-@@ -400,7 +402,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
- 			goto formerr;
- 
- 		/* Address. */
--		(void) inet_ntop(AF_INET, rdata, buf, buflen);
-+		if (inet_ntop (AF_INET, rdata, buf, buflen) == NULL)
-+		  return -1;
- 		addlen(strlen(buf), &buf, &buflen);
- 		rdata += NS_INADDRSZ;
- 
-@@ -542,7 +545,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
- 			if (rdata + pbyte >= edata) goto formerr;
- 			memset(&a, 0, sizeof(a));
- 			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
--			(void) inet_ntop(AF_INET6, &a, buf, buflen);
-+			if (inet_ntop (AF_INET6, &a, buf, buflen) == NULL)
-+			  return -1;
- 			addlen(strlen(buf), &buf, &buflen);
- 			rdata += sizeof(a) - pbyte;
- 		}

diff --git a/glibc-RHEL-172425-3.patch b/glibc-RHEL-172425-3.patch
deleted file mode 100644
index 0344f44..0000000
--- a/glibc-RHEL-172425-3.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-Taken from: <https://inbox.sourceware.org/libc-alpha/cover.1777546194.git.fweimer@redhat.com/>
-
-commit 7e090bee0c7a19274ac9b5ba1c27ef0165ed5bd7
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Thu Apr 30 12:52:07 2026 +0200
-
-    resolv: Remove incorrect parts of TSIG handling from ns_sprintrrf (CVE-2026-5435)
-    
-    TSIG handling was incomplete before.  Given that this is an obsolete
-    interface, it does not seem worthwhile to complete the implementation.
-    
-    This fixes bug 34033.
-
-diff --git a/resolv/ns_print.c b/resolv/ns_print.c
-index 5701e3d0c59f79f1..9c9e810781aaa4f4 100644
---- a/resolv/ns_print.c
-+++ b/resolv/ns_print.c
-@@ -513,17 +513,7 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
- 
- 	case ns_t_tsig: {
- 		/* BEW - need to complete this */
--		int n;
--
- 		T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
--		T(addstr(" ", 1, &buf, &buflen));
--		rdata += 8; /*%< time */
--		n = ns_get16(rdata); rdata += INT16SZ;
--		rdata += n; /*%< sig */
--		n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
--		sprintf(buf, "%d", ns_get16(rdata));
--		rdata += INT16SZ;
--		addlen(strlen(buf), &buf, &buflen);
- 		break;
- 	    }
- 

diff --git a/glibc-RHEL-172425-4.patch b/glibc-RHEL-172425-4.patch
deleted file mode 100644
index ac5e561..0000000
--- a/glibc-RHEL-172425-4.patch
+++ /dev/null
@@ -1,92 +0,0 @@
-Taken from: <https://inbox.sourceware.org/libc-alpha/cover.1777546194.git.fweimer@redhat.com/>
-
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Thu Apr 30 12:52:13 2026 +0200
-
-    resolv: Fix buffer overreads in ns_sprintrrf (CVE-2026-6238)
-    
-    Check that the RDATA payload does not require more than RDATALEN
-    bytes while processing it.  The fixes cover A6, CERT, LOC, TKEY,
-    TSIG records.
-    
-    The vulnerable LOC record handling was first introduced before
-    glibc 2.0, in commit ee188d555b8c32ad9704a7440cab400af967292f.
-    
-    CERT, TSIG, TKEY handling came with commit
-    b43b13ac2544b11f35be301d1589b51a8473e32b, released with glibc 2.2.
-    
-    A6 record handling was introduced in commit
-    91633816430e7ec5a19fe3ff510a7c4822a9557e ("* resolv/ns_print.c
-    (ns_sprintrrf): Handle ns_t_a6 and ns_t_opt."), which went into glibc
-    2.7.
-    
-    This fixes bug 34069.
-
-diff --git a/resolv/ns_print.c b/resolv/ns_print.c
-index 9c9e810781aaa4f4..4953f4716001d82b 100644
---- a/resolv/ns_print.c
-+++ b/resolv/ns_print.c
-@@ -318,7 +318,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
- 	case ns_t_loc: {
- 		char t[255];
- 
--		/* XXX protocol format checking? */
-+		if (rdlen != 16)
-+		  goto formerr;
- 		(void) loc_ntoa(rdata, t);
- 		T(addstr(t, strlen(t), &buf, &buflen));
- 		break;
-@@ -444,6 +445,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
- 		char base64_cert[8192], tmp[40];
- 		const char *leader;
- 
-+		if (rdlen < 2 * NS_INT16SZ + 1)
-+			goto formerr;
- 		c_type  = ns_get16(rdata); rdata += NS_INT16SZ;
- 		key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
- 		alg = (u_int) *rdata++;
-@@ -490,23 +493,31 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
- 		T(addstr(" ", 1, &buf, &buflen));
- 
- 		/* Inception. */
-+		if (edata - rdata < NS_INT32SZ)
-+			goto formerr;
- 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
- 		len = SPRINTF((tmp, "%lu ", t));
- 		T(addstr(tmp, len, &buf, &buflen));
- 
- 		/* Expiration. */
-+		if (edata - rdata < NS_INT32SZ)
-+			goto formerr;
- 		t = ns_get32(rdata);  rdata += NS_INT32SZ;
- 		len = SPRINTF((tmp, "%lu ", t));
- 		T(addstr(tmp, len, &buf, &buflen));
- 
- 		/* Mode , Error, Key Size. */
- 		/* Priority, Weight, Port. */
-+		if (edata - rdata < 3 * NS_INT16SZ)
-+			goto formerr;
- 		mode = ns_get16(rdata);  rdata += NS_INT16SZ;
- 		err  = ns_get16(rdata);  rdata += NS_INT16SZ;
- 		keysize  = ns_get16(rdata);  rdata += NS_INT16SZ;
- 		len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
- 		T(addstr(tmp, len, &buf, &buflen));
- 
-+		if (edata - rdata < keysize)
-+			goto formerr;
- 		/* XXX need to dump key, print otherdata length & other data */
- 		break;
- 	    }
-@@ -532,9 +543,10 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
- 
- 		/* address suffix: provided only when prefix len != 128 */
- 		if (pbit < 128) {
--			if (rdata + pbyte >= edata) goto formerr;
-+			unsigned int bytelen = sizeof(a) - pbyte;
-+			if (edata - rdata < bytelen) goto formerr;
- 			memset(&a, 0, sizeof(a));
--			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
-+			memcpy(&a.s6_addr[pbyte], rdata, bytelen);
- 			if (inet_ntop (AF_INET6, &a, buf, buflen) == NULL)
- 			  return -1;
- 			addlen(strlen(buf), &buf, &buflen);

diff --git a/glibc-RHEL-172425-5.patch b/glibc-RHEL-172425-5.patch
deleted file mode 100644
index 8cec001..0000000
--- a/glibc-RHEL-172425-5.patch
+++ /dev/null
@@ -1,363 +0,0 @@
-Taken from: <https://inbox.sourceware.org/libc-alpha/cover.1777546194.git.fweimer@redhat.com/>
-
-Author: Florian Weimer <fweimer@redhat.com>
-Date:   Thu Apr 30 12:52:18 2026 +0200
-
-    resolv: Add test case tst-ns_sprintrr (bug 34033, bug 34069)
-    
-    This test case covers both input buffer overreads and output buffer
-    overflows.  It should systematically cover these issues.
-    
-    I used code auto-generation for updating the test expectations for
-    truncated RDATA in TXT, ISDN, CERT records, after writing the rest
-    of the test by hand.
-    
-    Assisted-by: LLM
-
-diff --git a/resolv/Makefile b/resolv/Makefile
-index 971608eff50d0191..4b61d2ce98cf251f 100644
---- a/resolv/Makefile
-+++ b/resolv/Makefile
-@@ -108,6 +108,7 @@ tests += \
-   tst-ns_name \
-   tst-ns_name_compress \
-   tst-ns_name_pton \
-+  tst-ns_sprintrr \
-   tst-res_hconf_reorder \
-   tst-res_hnok \
-   tst-resolv-aliases \
-@@ -338,5 +339,6 @@ $(objpfx)tst-ns_name: $(objpfx)libresolv.so
- $(objpfx)tst-ns_name.out: tst-ns_name.data
- $(objpfx)tst-ns_name_compress: $(objpfx)libresolv.so
- $(objpfx)tst-ns_name_pton: $(objpfx)libresolv.so
-+$(objpfx)tst-ns_sprintrr: $(objpfx)libresolv.so
- $(objpfx)tst-res_hnok: $(objpfx)libresolv.so
- $(objpfx)tst-p_secstodate: $(objpfx)libresolv.so
-diff --git a/resolv/tst-ns_sprintrr.c b/resolv/tst-ns_sprintrr.c
-new file mode 100644
-index 0000000000000000..522d835fe6f63df2
---- /dev/null
-+++ b/resolv/tst-ns_sprintrr.c
-@@ -0,0 +1,322 @@
-+/* Tests for the ns_sprintrr function.
-+   Copyright (C) 2026 Free Software Foundation, Inc.
-+   This file is part of the GNU C Library.
-+
-+   The GNU C Library is free software; you can redistribute it and/or
-+   modify it under the terms of the GNU Lesser General Public
-+   License as published by the Free Software Foundation; either
-+   version 2.1 of the License, or (at your option) any later version.
-+
-+   The GNU C Library 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
-+   Lesser General Public License for more details.
-+
-+   You should have received a copy of the GNU Lesser General Public
-+   License along with the GNU C Library; if not, see
-+   <https://www.gnu.org/licenses/>.  */
-+
-+#include <arpa/nameser.h>
-+
-+#include <alloc_buffer.h>
-+#include <arpa/inet.h>
-+#include <libc-diag.h>
-+#include <stdbool.h>
-+#include <string.h>
-+#include <support/check.h>
-+#include <support/next_to_fault.h>
-+
-+/* Regions that test_one_record uses for input and output.  */
-+static struct support_next_to_fault ntf_in;
-+static struct support_next_to_fault ntf_out;
-+
-+/* This is used by test_one_record to construct the packet.   */
-+static const char packet_prefix[] =
-+  /* DNS response with one question, one answer record.  */
-+  "AA\x81\x80\0\1\0\1\0\0\0\0"
-+  /* Question: www.example.org/IN/ANY.  */
-+  "\3www\7example\3org\0\0\xff\0\1"
-+  /* Response: compression reference.  */
-+  "\xc0\x0c";
-+
-+/* Use ns_sprintrr to format a DNS record (starting with
-+   packet_prefix) of type RTYPE, with a record payload of RDATALEN
-+   bytes starting at RDATA.  Check successful formatting against
-+   EXPECTED.  Try various truncated input and output buffers to catch
-+   overreads and buffer overflows, using ntf_in and ntf_out above.  */
-+static void
-+test_one_record (uint16_t rtype, const char *rdata, size_t rdatalen,
-+                 const char *expected)
-+{
-+  struct rr_header
-+  {
-+    uint16_t typ;
-+    uint16_t cls;
-+    uint32_t ttl;
-+    uint16_t rdatalen;
-+    uint16_t pad;
-+  } hdr =
-+    {
-+      .typ = htons (rtype),
-+      .cls = htons (ns_c_in),
-+      .ttl = htonl (86400),     /* One day.  */
-+      .rdatalen = htons (rdatalen),
-+    };
-+  size_t hdrlen = offsetof (struct rr_header, pad);
-+  TEST_COMPARE (hdrlen, 10);
-+
-+  /* Construct the packet from packet_prefix, hdr, and rdata.  */
-+  char packet[512];
-+  size_t packetlen;
-+  {
-+    struct alloc_buffer buf = alloc_buffer_create (packet, sizeof (packet));
-+    alloc_buffer_copy_bytes (&buf, packet_prefix, sizeof (packet_prefix) - 1);
-+    alloc_buffer_copy_bytes (&buf, &hdr, hdrlen);
-+    alloc_buffer_copy_bytes (&buf, rdata, rdatalen);
-+    packetlen = sizeof (packet) - alloc_buffer_size (&buf);
-+  }
-+
-+  /* Parse the record.   */
-+  ns_msg msg;
-+  TEST_COMPARE (ns_initparse ((unsigned char *) packet, packetlen, &msg), 0);
-+  ns_rr rr;
-+  TEST_COMPARE (ns_parserr (&msg, ns_s_an, 0, &rr), 0);
-+
-+  /* Try sizes up to this limit.  Go a bit beyond the expected size to
-+     check for errors.  */
-+  size_t max_result_size = strlen (expected) + 16;
-+
-+  bool success = false;
-+  for (size_t result_size = 1; result_size <= max_result_size; ++result_size)
-+    {
-+      char *result_start = ntf_out.buffer + ntf_out.length - result_size;
-+      memset (result_start, 'X', result_size);
-+
-+      /* ns_sprintrr was deprecated in 2.34.  */
-+      DIAG_PUSH_NEEDS_COMMENT;
-+      DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations");
-+      int ret = ns_sprintrr (&msg, &rr, NULL, NULL, result_start, result_size);
-+      DIAG_POP_NEEDS_COMMENT;
-+
-+      if (ret > 0)
-+        {
-+          TEST_COMPARE_STRING (result_start, expected);
-+          TEST_COMPARE (ret, strlen (expected));
-+          success = true;
-+        }
-+      else
-+        {
-+          TEST_VERIFY (!success);
-+          TEST_COMPARE (ret, -1);
-+        }
-+    }
-+  TEST_VERIFY (success);
-+
-+  /* Test with truncated RDATA.   */
-+  for (size_t rdata_size = 0; rdata_size <= rdatalen; ++rdata_size)
-+    {
-+      size_t truncated_packet_size = packetlen - rdatalen + rdata_size;
-+      char *packet_start
-+        = ntf_in.buffer + ntf_in.length - truncated_packet_size;
-+      memcpy (packet_start, packet, truncated_packet_size);
-+      /* Patch in the updated RDATA length field.  */
-+      uint16_t new_rdatalen = htons (rdata_size);
-+      memcpy (packet_start + truncated_packet_size - rdata_size - 2,
-+              &new_rdatalen, 2);
-+
-+      ns_msg msg;
-+      TEST_COMPARE (ns_initparse ((unsigned char *) packet_start,
-+                                  truncated_packet_size, &msg), 0);
-+      ns_rr rr;
-+      TEST_COMPARE (ns_parserr (&msg, ns_s_an, 0, &rr), 0);
-+
-+      size_t result_size = strlen (expected) + 1;
-+      char *result_start = ntf_out.buffer + ntf_out.length - result_size;
-+      memset (result_start, 'X', result_size);
-+
-+      /* ns_sprintrr was deprecated in 2.34.  */
-+      DIAG_PUSH_NEEDS_COMMENT;
-+      DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations");
-+      int ret = ns_sprintrr (&msg, &rr, NULL, NULL, result_start, result_size);
-+      DIAG_POP_NEEDS_COMMENT;
-+
-+      /* This flag indicates whether the output is syntactically
-+         correct.  In some cases, truncation may still yield a valid
-+         payload.  */
-+      bool broken = rdata_size < rdatalen;
-+      switch (rtype)
-+        {
-+        case ns_t_wks:
-+          /* WKS records use all trailing bytes for the port bitmap.  */
-+          broken = rdata_size < 5;
-+          break;
-+        case ns_t_nsap:
-+          /* Uses all bytes that are available.  */
-+          broken = false;
-+          break;
-+        case ns_t_txt:
-+          /* Truncation produces a valid payload if it occurs right
-+             after a complete string in the TXT payload.  */
-+          broken = false;
-+          for (size_t pos = 0; pos < rdata_size; )
-+            {
-+              unsigned int slen = rdata[pos] & 0xff;
-+              if (pos + 1 + slen > rdata_size)
-+                {
-+                  broken = true;
-+                  break;
-+                }
-+              pos += 1 + slen;
-+            }
-+          break;
-+        case ns_t_isdn:
-+          /* The second field is optional.  If it is present, it must
-+             not be truncated.  */
-+          broken = rdata_size < 6 || (rdata_size > 6 && rdata_size < rdatalen);
-+          break;
-+        case ns_t_cert:
-+          /* The 5-byte header is sufficient. Any available trailing
-+             data is base64-encoded.  */
-+          broken = rdata_size < 5;
-+          break;
-+        case ns_t_a6:
-+          /* The first A6 subtest contains a trailing domain name,
-+             which is ignored and not formatted.  */
-+          if (rdata_size > 0 && rdata[0] == 0)
-+            broken = rdata_size < 17;
-+          break;
-+        }
-+
-+      if (broken)
-+        {
-+          if (strstr (result_start, "RR format error") != NULL)
-+            /* No further checks if an error indicator has been added
-+               to the output.  */
-+            ;
-+          /* TKEY and TSIG implementations are incomplete.  */
-+          else if (rtype != ns_t_tkey && rtype != ns_t_tsig)
-+            TEST_COMPARE (ret, -1);
-+        }
-+      else
-+        TEST_VERIFY (ret > 0);
-+    }
-+}
-+
-+static int
-+do_test (void)
-+{
-+  ntf_in = support_next_to_fault_allocate (512);
-+  ntf_out = support_next_to_fault_allocate (256);
-+
-+#define T(rtype, rdata, expected) \
-+  test_one_record (rtype, rdata, sizeof (rdata) - 1, expected)
-+  T (ns_t_a, "\xc0\0\2\1", "www.example.org.\t1D IN A\t\t192.0.2.1");
-+  T (ns_t_cname, "\4www1\4prod\xc0\x10",
-+     "www.example.org.\t1D IN CNAME\twww1.prod.example.org.");
-+  T (ns_t_hinfo, "\5first\6second",
-+     "www.example.org.\t1D IN HINFO\t\"first\" \"second\"");
-+  T (ns_t_isdn, "\5first\6second",
-+     "www.example.org.\t1D IN ISDN\t\"first\" \"second\"");
-+  /* Bug: Extra space at the end in the text representation of ISDN RRs.  */
-+  T (ns_t_isdn, "\5first", "www.example.org.\t1D IN ISDN\t\"first\" ");
-+  T (ns_t_soa,
-+     "\2ns\xc0\x10\12hostmaster\xc0\x10"
-+     "\0\0\0\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5",
-+     "www.example.org.\t1D IN SOA\tns.example.org. hostmaster.example.org. (\n"
-+     "\t\t\t\t\t1\t\t; serial\n"
-+     "\t\t\t\t\t2S\t\t; refresh\n"
-+     "\t\t\t\t\t3S\t\t; retry\n"
-+     "\t\t\t\t\t4S\t\t; expiry\n"
-+     "\t\t\t\t\t5S )\t\t; minimum\n");
-+  T (ns_t_mx, "\0\xa\2mx\xc0\x10",
-+     "www.example.org.\t1D IN MX\t10 mx.example.org.");
-+  T (ns_t_px, "\0\xa\3px1\xc0\x10\3px2\xc0\x10",
-+     "www.example.org.\t1D IN PX\t10 px1.example.org. px2.example.org.");
-+  T (ns_t_x25, "\4X.25",
-+     "www.example.org.\t1D IN X25\t\"X.25\"");
-+  T (ns_t_txt, "\1A\2BC\3DEF",
-+     "www.example.org.\t1D IN TXT\t\"A\" \"BC\" \"DEF\"");
-+  T (ns_t_nsap, "",
-+     "www.example.org.\t1D IN NSAP\t");
-+  T (ns_t_nsap, "\1",
-+     "www.example.org.\t1D IN NSAP\t01");
-+  T (ns_t_nsap, "\1\2",
-+     "www.example.org.\t1D IN NSAP\t01.02");
-+  T (ns_t_nsap, "\1\2\3",
-+     "www.example.org.\t1D IN NSAP\t01.0203");
-+  T (ns_t_nsap, "\1\2\3\4",
-+     "www.example.org.\t1D IN NSAP\t01.0203.04");
-+  T (ns_t_nsap,
-+     "\1\2\3\4\5\6\7\10\11\12\13\14\15\16\17\20\21\22\23\24\25\26\27\30\31\32"
-+     "\33\34\35\36\37\40\41\42\43\44\45\46\47\50\51\52\53\54\55\56\57\60\61"
-+     "\62\63\64\65\66\67\70\71\72\73\74\75\76\77\100\101\102\103\104\105\106"
-+     "\107\110\111\112\113\114\115\116\117\120\121\122\123\124\125\126\127"
-+     "\130\131\132\133\134\135\136\137\140\141\142\143\144\145\146\147\150"
-+     "\151\152\153\154\155\156\157\160\161\162\163\164\165\166\167\170\171"
-+     "\172\173\174\175\176\177\200\201\202\203\204\205\206\207\210\211\212"
-+     "\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233"
-+     "\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254"
-+     "\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275"
-+     "\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316"
-+     "\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337"
-+     "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360"
-+     "\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",
-+     "www.example.org.\t1D IN NSAP\t"
-+     "01.0203.0405.0607.0809.0A0B.0C0D.0E0F.1011.1213.1415.1617.1819.1A1B"
-+     ".1C1D.1E1F.2021.2223.2425.2627.2829.2A2B.2C2D.2E2F.3031.3233.3435.3637"
-+     ".3839.3A3B.3C3D.3E3F.4041.4243.4445.4647.4849.4A4B.4C4D.4E4F.5051.5253"
-+     ".5455.5657.5859.5A5B.5C5D.5E5F.6061.6263.6465.6667.6869.6A6B.6C6D.6E6F"
-+     ".7071.7273.7475.7677.7879.7A7B.7C7D.7E7F.8081.8283.8485.8687.8889.8A8B"
-+     ".8C8D.8E8F.9091.9293.9495.9697.9899.9A9B.9C9D.9E9F.A0A1.A2A3.A4A5.A6A7"
-+     ".A8A9.AAAB.ACAD.AEAF.B0B1.B2B3.B4B5.B6B7.B8B9.BABB.BCBD.BEBF.C0C1.C2C3"
-+     ".C4C5.C6C7.C8C9.CACB.CCCD.CECF.D0D1.D2D3.D4D5.D6D7.D8D9.DADB.DCDD.DEDF"
-+     ".E0E1.E2E3.E4E5.E6E7.E8E9.EAEB.ECED.EEEF.F0F1.F2F3.F4F5.F6F7.F8F9.FAFB"
-+     ".FCFD.FEFF");
-+  T (ns_t_aaaa, "\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x34",
-+     "www.example.org.\t1D IN AAAA\t2001:db8::1234");
-+  /* Example from RFC 1876.  The loc_ntoa format is different from the
-+     official text representation.  */
-+  T (ns_t_loc,
-+     "\000\063\026\023\211\027\055\320\160\276\025\360\000\230\215\040",
-+     "www.example.org.\t1D IN LOC"
-+     "\t42 21 54.000 N 71 06 18.000 W -24.00m 30.00m 10000.00m 10.00m");
-+  T (ns_t_naptr,
-+     "\0\1\0\2\5flags\7service\2.*\5naptr\xc0\x10",
-+     "www.example.org.\t1D IN NAPTR\t1 2 \"flags\" \"service\" \".*\""
-+     " naptr.example.org.");
-+  T (ns_t_srv,
-+     "\0\1\0\2\0\x50\4www1\xc0\x10",
-+     "www.example.org.\t1D IN SRV\t1 2 80 www1.example.org.");
-+  T (ns_t_rp, "\3rp1\xc0\x10\3rp2\xc0\x10",
-+     "www.example.org.\t1D IN RP\trp1.example.org. rp2.example.org.");
-+  T (ns_t_wks, "\xc0\0\2\1\6\0\0\0\0\0\0\0\0\0\0\200",
-+     "www.example.org.\t1D IN WKS\t192.0.2.1 6 ( \n\t\t\t\t80 )");
-+  T (ns_t_cert, "\0\1\x04\xd2\0blob",
-+     "www.example.org.\t1D IN CERT\t1 1234 0  YmxvYg==");
-+  /* Bug: TKEY output is incomplete.  */
-+  T (ns_t_tkey, "\4algo\0\0\0\0\1\0\0\0\2\0\3\0\4"
-+     "\0\5\xa1\xa2\xa3\xa4\xa5\0\3\xb1\xb2\xb3",
-+     "www.example.org.\t1D IN 249\talgo. 1 2 3 4 5 ");
-+  /* Bug: Not implemented properly.  */
-+  T (ns_t_tsig, "\4algo\0"
-+     "\0\20\xdd\xcd\x64\x10\xe9\x21\x34\x1a\x8e\xe0\xa1\x9a\x30\xfc\x3b\xd1"
-+     "\0\2\0\3\0\5other",
-+     "www.example.org.\t1D IN TSIG\talgo.");
-+  T (ns_t_a6,
-+     "\0\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x34\6prefix\xc0\x10",
-+     "www.example.org.\t1D IN 38\t0 2001:db8::1234");
-+  T (ns_t_a6,
-+     "\0\x20\x01\x0d\xb8\0\0\0\0\0\0\0\0\0\0\x12\x34",
-+     "www.example.org.\t1D IN 38\t0 2001:db8::1234");
-+  T (ns_t_a6, "\200\6prefix\xc0\x10",
-+     "www.example.org.\t1D IN 38\t128  prefix.example.org.");
-+  T (ns_t_a6, "\x20\0\0\0\0\0\0\0\0\0\0\x12\x34\6prefix\xc0\x10",
-+     "www.example.org.\t1D IN 38\t32 ::1234 prefix.example.org.");
-+#undef T
-+
-+  support_next_to_fault_free (&ntf_in);
-+  support_next_to_fault_free (&ntf_out);
-+  return 0;
-+}
-+
-+#include <support/test-driver.c>

diff --git a/glibc.spec b/glibc.spec
index 773dc50..d32d4ea 100644
--- a/glibc.spec
+++ b/glibc.spec
@@ -1,4 +1,4 @@
-%global glibcsrcdir glibc-2.43.9000-409-ga767fbcff0
+%global glibcsrcdir glibc-2.43.9000-444-gb61b98e3d0
 %global glibcversion 2.43.9000
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
@@ -152,7 +152,7 @@ Version: %{glibcversion}
 # - It allows using the Release number without the %%dist tag in the dependency
 #   generator to make the generated requires interchangeable between Rawhide
 #   and ELN (.elnYY < .fcXX).
-%global baserelease 21
+%global baserelease 22
 Release: %{baserelease}%{?dist}
 
 # Licenses:
@@ -349,11 +349,6 @@ Patch17: glibc-cs-path.patch
 Patch18: glibc-rh2426825.patch
 Patch19: glibc-rh2457183-1.patch
 Patch20: glibc-rh2457183-2.patch
-Patch22: glibc-RHEL-172425-1.patch
-Patch23: glibc-RHEL-172425-2.patch
-Patch24: glibc-RHEL-172425-3.patch
-Patch25: glibc-RHEL-172425-4.patch
-Patch26: glibc-RHEL-172425-5.patch
 
 ##############################################################################
 # Continued list of core "glibc" package information:
@@ -2409,6 +2404,51 @@ update_gconv_modules_cache ()
 %endif
 
 %changelog
+* Tue Jun 23 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-22
+- Auto-sync with upstream branch master,
+  commit b61b98e3d0c81c85200e2082407708c7b0e821a3:
+- resolv: Add test for gethostbyname_r unaligned buffer [BZ #18287] (Sergey Kolosov)
+- Define _PATH_MOUNTED as "/etc/mtab" (Justus Winter)
+- Add advisory text for CVE-2026-6791 (Adhemerval Zanella)
+- posix: Fix stack overflow in wordexp tilde expansion (BZ 34091, CVE-2026-6791) (Adhemerval Zanella)
+- riscv: Add RVV memmove for both multiarch and non-multiarch builds (Yao Zihong)
+- elf: Support THP segment load with madvise enabled THP (H.J. Lu)
+- advisories: Update GLIBC-SA-2026-0012 metadata (Carlos O'Donell)
+- Remove unused THREAD_SET_POINTER_GUARD and THREAD_COPY_POINTER_GUARD (Adhemerval Zanella)
+- resolv: Add test case tst-ns_sprintrr (bug 34033, bug 34069) (Florian Weimer)
+- resolv: Fix buffer overreads in ns_sprintrrf (CVE-2026-6238) (Florian Weimer)
+- resolv: More types as unknown in ns_sprintrrf (CVE-2026-5435) (Florian Weimer)
+- resolv: Check for inet_ntop failure in ns_sprintrrf (Florian Weimer)
+- resolv: Improve formatting of unknown records in ns_sprintrrf (Florian Weimer)
+- resolv: Fix ns_sprintrrf formatting of class, type values (bug 34289) (Florian Weimer)
+- resolv: Declare __p_class_syms, __p_type_syms for internal use (Florian Weimer)
+- Update GLIBC-SA-2026-0012 to mention A6 records (Florian Weimer)
+- string: Improve memchr random test (Wilco Dijkstra)
+- AArch64: Vectorise SVE fp64 sin/cos special case (Dylan Fleming)
+- AArch64: Vectorise AdvSIMD fp64 sin/cos special case (Dylan Fleming)
+- AArch64: Vectorise SVE fp32 sin/cos special case (Dylan Fleming)
+- AArch64: Vectorise AdvSIMD fp32 sin/cos special case (Dylan Fleming)
+- news: Describe AArch64-specific changes for 2.44 (Yury Khrustalev)
+- elf: Do not scrub AT_RANDOM to a constant when reseeding fails (BZ 34197) (Adhemerval Zanella)
+- manual: Update memchr description [BZ #19406] (Wilco Dijkstra)
+- hurd: Add ETH_TLEN and ETH_FCS_LEN (Samuel Thibault)
+- hurd: Fix ETH_P_PUP (Samuel Thibault)
+- Factorize if_arp.h (Samuel Thibault)
+- elf: Scrub and reseed the AT_RANDOM bytes after deriving the guards (BZ 34197) (Adhemerval Zanella)
+- Consolidate dl-osinfo.h into the generic implementation (Adhemerval Zanella)
+- Consolidate the C pointer guard and align the assembly implementations (Adhemerval Zanella)
+- Remove the jmp_buf stack pointer demangle on ABIs that do not mangle it (Adhemerval Zanella)
+- Split pointer_guard.h into C and assembly headers (Adhemerval Zanella)
+- Enable the pointer guard in the dynamic loader (Adhemerval Zanella)
+- Consolidate pointer guard to use a relro variable instead of the TCB (Adhemerval Zanella)
+- elf: Propagate the pointer guard to ld.so loaded via static dlopen (BZ 34196) (Adhemerval Zanella)
+- Remove applied or redundant patches:
+  - glibc-RHEL-172425-1.patch
+  - glibc-RHEL-172425-2.patch
+  - glibc-RHEL-172425-3.patch
+  - glibc-RHEL-172425-4.patch
+  - glibc-RHEL-172425-5.patch
+
 * Tue Jun 16 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-21
 - Auto-sync with upstream branch master,
   commit a767fbcff0eefc64cb6b2369a34b5205468dbafd:

diff --git a/sources b/sources
index dd0accb..40a3a6b 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (glibc-2.43.9000-409-ga767fbcff0.tar.xz) = 3e8655607179acb087cfe636c3f09c91b34bd789faad7b38470a17d648895d567d2d33b19450cb76bb27ca6474f82f84e9f05e6e81b0b814b91351032e64c615
+SHA512 (glibc-2.43.9000-444-gb61b98e3d0.tar.xz) = debf5148d5fc79bc60897fbed69d68df1d82d006be520970f613b35512c390a4589b2dd684568ac4cd63f9bab109feada68463a8b4f580a16f8c5f330562060f

^ permalink raw reply related	[flat|nested] 7+ messages in thread
* [rpms/glibc] rawhide: Auto-sync with upstream branch master
@ 2026-06-16 13:09 
  0 siblings, 0 replies; 7+ messages in thread
From:  @ 2026-06-16 13:09 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/glibc
            Branch : rawhide
            Commit : fa4733c2e04904e9dc9b7cc71bb8d88f2ec00507
            Author : Frédéric Bérat <fberat@redhat.com>
            Date   : 2026-06-16T08:51:48+02:00
            Stats  : +18/-3 in 2 file(s)
            URL    : https://src.fedoraproject.org/rpms/glibc/c/fa4733c2e04904e9dc9b7cc71bb8d88f2ec00507?branch=rawhide

            Log:
            Auto-sync with upstream branch master

Upstream commit: a767fbcff0eefc64cb6b2369a34b5205468dbafd

- math: Sync acosh with CORE-MATH 887cab6f (Adhemerval Zanella)
- inet: Remove unused STATIC_NSS define (Michael Ford)
- nss: Remove <gnu/lib-names.h> include from nsswitch.c (Michael Ford)
- arm: Save/restore VFP registers in PLT trampolines (BZ 34144, BZ 15792) (Adhemerval Zanella)
- aarch64: Fix static PIE CPU feature detection (BZ 34205) (Adhemerval Zanella)
- nptl: open threads comm with O_WRONLY|O_CLOEXEC (Sana Kazi)
- malloc: aarch64: Add ifuncs for malloc functions (Yury Khrustalev)
- rtld: cache cpuid results on the stack for intel (Fabian Rast)
- Fix -Wconstant-logical-operand error for Hurd (Joseph Myers)
- Fix -Werror=constant-logical-operand errors in soft-fp (Joseph Myers)
- Fix -Wconstant-logical-operand error in tst-printf-format-skeleton.c (Joseph Myers)

---
diff --git a/glibc.spec b/glibc.spec
index c7d99d5..2329bc6 100644
--- a/glibc.spec
+++ b/glibc.spec
@@ -1,4 +1,4 @@
-%global glibcsrcdir glibc-2.43.9000-398-g9cf4dd03bd
+%global glibcsrcdir glibc-2.43.9000-409-ga767fbcff0
 %global glibcversion 2.43.9000
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
@@ -152,7 +152,7 @@ Version: %{glibcversion}
 # - It allows using the Release number without the %%dist tag in the dependency
 #   generator to make the generated requires interchangeable between Rawhide
 #   and ELN (.elnYY < .fcXX).
-%global baserelease 20
+%global baserelease 21
 Release: %{baserelease}%{?dist}
 
 # Licenses:
@@ -2408,6 +2408,21 @@ update_gconv_modules_cache ()
 %endif
 
 %changelog
+* Tue Jun 16 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-21
+- Auto-sync with upstream branch master,
+  commit a767fbcff0eefc64cb6b2369a34b5205468dbafd:
+- math: Sync acosh with CORE-MATH 887cab6f (Adhemerval Zanella)
+- inet: Remove unused STATIC_NSS define (Michael Ford)
+- nss: Remove <gnu/lib-names.h> include from nsswitch.c (Michael Ford)
+- arm: Save/restore VFP registers in PLT trampolines (BZ 34144, BZ 15792) (Adhemerval Zanella)
+- aarch64: Fix static PIE CPU feature detection (BZ 34205) (Adhemerval Zanella)
+- nptl: open threads comm with O_WRONLY|O_CLOEXEC (Sana Kazi)
+- malloc: aarch64: Add ifuncs for malloc functions (Yury Khrustalev)
+- rtld: cache cpuid results on the stack for intel (Fabian Rast)
+- Fix -Wconstant-logical-operand error for Hurd (Joseph Myers)
+- Fix -Werror=constant-logical-operand errors in soft-fp (Joseph Myers)
+- Fix -Wconstant-logical-operand error in tst-printf-format-skeleton.c (Joseph Myers)
+
 * Wed Jun 10 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-20
 - Auto-sync with upstream branch master,
   commit 9cf4dd03bdfd8b4113400e6b56c6d665c3c739ae:

diff --git a/sources b/sources
index 409a614..dd0accb 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (glibc-2.43.9000-398-g9cf4dd03bd.tar.xz) = 1897f4087aefdda2e79fc8eeb2cf8a71b3ec516d37e9c0709b50758a7475a3594e5395a81f39fff1746dfbd84b5a8fb5e2f35a058bbcd66f02b3aa3b1a299ef2
+SHA512 (glibc-2.43.9000-409-ga767fbcff0.tar.xz) = 3e8655607179acb087cfe636c3f09c91b34bd789faad7b38470a17d648895d567d2d33b19450cb76bb27ca6474f82f84e9f05e6e81b0b814b91351032e64c615

^ permalink raw reply related	[flat|nested] 7+ messages in thread
* [rpms/glibc] rawhide: Auto-sync with upstream branch master
@ 2026-06-10 15:23 
  0 siblings, 0 replies; 7+ messages in thread
From:  @ 2026-06-10 15:23 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/glibc
            Branch : rawhide
            Commit : b960794566d3cd7a6a559484efb10ce37085c7a9
            Author : Frédéric Bérat <fberat@redhat.com>
            Date   : 2026-06-10T10:43:55+02:00
            Stats  : +30/-3 in 2 file(s)
            URL    : https://src.fedoraproject.org/rpms/glibc/c/b960794566d3cd7a6a559484efb10ce37085c7a9?branch=rawhide

            Log:
            Auto-sync with upstream branch master

Upstream commit: 9cf4dd03bdfd8b4113400e6b56c6d665c3c739ae

- riscv: Keep __memcmpeq alias with RVV memcmp (Zihong Yao)
- fcntl-linux.h : Fix typo in comments. (bug 17119) (Brian Jorgensen)
- iconv: Suppress intermediate errors with //TRANSLIT (bug 34236) (Florian Weimer)
- nscd: Typo in comment (Josef Johansson)
- libio: use _IO_have_wbackup for wide streams (Andreas Schwab)
- elf: don't clobber ld.so.conf in tst-glibc-hwcaps-prepend-cache [BZ #34210] (Sam James)
- elf: Remove inhibit_stack_protector from __ifunc_resolver (Adhemerval Zanella)
- elf: Set up TLS slotinfo for dlopen'd modules before relocation (BZ 34170) (Adhemerval Zanella)
- malloc: Simplify _int_free_chunk (Wilco Dijkstra)
- riscv: Add RVV strrchr for both multiarch and non-multiarch builds (Yao Zihong)
- riscv: Add RVV strchr for both multiarch and non-multiarch builds (Yao Zihong)
- riscv: Add RVV memchr for both multiarch and non-multiarch builds (Yao Zihong)
- riscv: Add RVV memccpy for both multiarch and non-multiarch builds (Yao Zihong)
- riscv: Add RVV memcmp for both multiarch and non-multiarch builds (Yao Zihong)
- malloc: Reduce maximum arenas (Wilco Dijkstra)
- resolv: reset _u._ext.nscount in __res_iclose [BZ #34154] (Adam Yi)
- sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c: Fix typo (Alejandro Colomar)
- malloc: Improve documentation of malloc tunables (Wilco Dijkstra)
- malloc: Minor cleanups (Wilco Dijkstra)
- support: Also run malloc hugetlb=1 tests when transparent hugepage is 'always' (Adhemerval Zanella)
- arm: Fix main-in-dso with non-BFD linkers (BZ 34098) (Adhemerval Zanella)
- elf: Fix tst-ifunc-tls-init with --disable-default-pie (Adhemerval Zanella)
- powerpc64le: Add optimized __memcmpeq for POWER10 (Sachin Monga)

---
diff --git a/glibc.spec b/glibc.spec
index bc63a4f..c7d99d5 100644
--- a/glibc.spec
+++ b/glibc.spec
@@ -1,4 +1,4 @@
-%global glibcsrcdir glibc-2.43.9000-375-gc5278a6428
+%global glibcsrcdir glibc-2.43.9000-398-g9cf4dd03bd
 %global glibcversion 2.43.9000
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
@@ -152,7 +152,7 @@ Version: %{glibcversion}
 # - It allows using the Release number without the %%dist tag in the dependency
 #   generator to make the generated requires interchangeable between Rawhide
 #   and ELN (.elnYY < .fcXX).
-%global baserelease 19
+%global baserelease 20
 Release: %{baserelease}%{?dist}
 
 # Licenses:
@@ -2408,6 +2408,33 @@ update_gconv_modules_cache ()
 %endif
 
 %changelog
+* Wed Jun 10 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-20
+- Auto-sync with upstream branch master,
+  commit 9cf4dd03bdfd8b4113400e6b56c6d665c3c739ae:
+- riscv: Keep __memcmpeq alias with RVV memcmp (Zihong Yao)
+- fcntl-linux.h : Fix typo in comments. (bug 17119) (Brian Jorgensen)
+- iconv: Suppress intermediate errors with //TRANSLIT (bug 34236) (Florian Weimer)
+- nscd: Typo in comment (Josef Johansson)
+- libio: use _IO_have_wbackup for wide streams (Andreas Schwab)
+- elf: don't clobber ld.so.conf in tst-glibc-hwcaps-prepend-cache [BZ #34210] (Sam James)
+- elf: Remove inhibit_stack_protector from __ifunc_resolver (Adhemerval Zanella)
+- elf: Set up TLS slotinfo for dlopen'd modules before relocation (BZ 34170) (Adhemerval Zanella)
+- malloc: Simplify _int_free_chunk (Wilco Dijkstra)
+- riscv: Add RVV strrchr for both multiarch and non-multiarch builds (Yao Zihong)
+- riscv: Add RVV strchr for both multiarch and non-multiarch builds (Yao Zihong)
+- riscv: Add RVV memchr for both multiarch and non-multiarch builds (Yao Zihong)
+- riscv: Add RVV memccpy for both multiarch and non-multiarch builds (Yao Zihong)
+- riscv: Add RVV memcmp for both multiarch and non-multiarch builds (Yao Zihong)
+- malloc: Reduce maximum arenas (Wilco Dijkstra)
+- resolv: reset _u._ext.nscount in __res_iclose [BZ #34154] (Adam Yi)
+- sysdeps/ieee754/ldbl-128ibm-compat/test-printf-chk-ldbl-compat.c: Fix typo (Alejandro Colomar)
+- malloc: Improve documentation of malloc tunables (Wilco Dijkstra)
+- malloc: Minor cleanups (Wilco Dijkstra)
+- support: Also run malloc hugetlb=1 tests when transparent hugepage is 'always' (Adhemerval Zanella)
+- arm: Fix main-in-dso with non-BFD linkers (BZ 34098) (Adhemerval Zanella)
+- elf: Fix tst-ifunc-tls-init with --disable-default-pie (Adhemerval Zanella)
+- powerpc64le: Add optimized __memcmpeq for POWER10 (Sachin Monga)
+
 * Tue Jun 02 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-19
 - Auto-sync with upstream branch master,
   commit c5278a64282f1c1f9a88711bac7b4e1469f851d6:

diff --git a/sources b/sources
index d8fe9f6..409a614 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (glibc-2.43.9000-375-gc5278a6428.tar.xz) = 4df2b3c42293ca3365a7ad676d2ae338a74bfe0d7ac69b9c039ff5856c3ff1cdf3d42437e8260a74ab483ead18d21e81ee6b780afe54e377155c25df29d0230d
+SHA512 (glibc-2.43.9000-398-g9cf4dd03bd.tar.xz) = 1897f4087aefdda2e79fc8eeb2cf8a71b3ec516d37e9c0709b50758a7475a3594e5395a81f39fff1746dfbd84b5a8fb5e2f35a058bbcd66f02b3aa3b1a299ef2

^ permalink raw reply related	[flat|nested] 7+ messages in thread
* [rpms/glibc] rawhide: Auto-sync with upstream branch master
@ 2026-06-02  7:31 
  0 siblings, 0 replies; 7+ messages in thread
From:  @ 2026-06-02  7:31 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/glibc
            Branch : rawhide
            Commit : cbc59f38e2362e47e0d9aa8c47d00c26cf37f587
            Author : Frédéric Bérat <fberat@redhat.com>
            Date   : 2026-06-02T03:01:58+02:00
            Stats  : +18/-3 in 2 file(s)
            URL    : https://src.fedoraproject.org/rpms/glibc/c/cbc59f38e2362e47e0d9aa8c47d00c26cf37f587?branch=rawhide

            Log:
            Auto-sync with upstream branch master

Upstream commit: c5278a64282f1c1f9a88711bac7b4e1469f851d6

- arm: Redirect memcpy to __memcpy_arm for loader/static init code (Adhemerval Zanella)
- misc: Fix typos in comments (Yury Khrustalev)
- hurd: define SO_TIMESTAMP in socket.h (Diego Nieto Cid)
- malloc: aarch64: Remove broken memory tagging (Yury Khrustalev)
- hesiod: use booleans in parser macro calls (Adhemerval Zanella)
- hesiod: fix swapped arguments in service parser (Adhemerval Zanella)
- math: Fix non-narrowing test build with arg-format conditions (Adhemerval Zanella)
- aarch64: Use build attributes for asm feature marking (Muhammad Kamran)
- misc: add a new test for gethostname (Martin Coufal)
- test: Fix and stabilize tst-wcsmbs-clone-overflow test (Frédéric Bérat)
- math: Fix fma alignment when exponent difference is exactly 64 (BZ 34183) (Adhemerval Zanella)

---
diff --git a/glibc.spec b/glibc.spec
index 1f87180..bc63a4f 100644
--- a/glibc.spec
+++ b/glibc.spec
@@ -1,4 +1,4 @@
-%global glibcsrcdir glibc-2.43.9000-364-gb20b94006c
+%global glibcsrcdir glibc-2.43.9000-375-gc5278a6428
 %global glibcversion 2.43.9000
 # Pre-release tarballs are pulled in from git using a command that is
 # effectively:
@@ -152,7 +152,7 @@ Version: %{glibcversion}
 # - It allows using the Release number without the %%dist tag in the dependency
 #   generator to make the generated requires interchangeable between Rawhide
 #   and ELN (.elnYY < .fcXX).
-%global baserelease 18
+%global baserelease 19
 Release: %{baserelease}%{?dist}
 
 # Licenses:
@@ -2408,6 +2408,21 @@ update_gconv_modules_cache ()
 %endif
 
 %changelog
+* Tue Jun 02 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-19
+- Auto-sync with upstream branch master,
+  commit c5278a64282f1c1f9a88711bac7b4e1469f851d6:
+- arm: Redirect memcpy to __memcpy_arm for loader/static init code (Adhemerval Zanella)
+- misc: Fix typos in comments (Yury Khrustalev)
+- hurd: define SO_TIMESTAMP in socket.h (Diego Nieto Cid)
+- malloc: aarch64: Remove broken memory tagging (Yury Khrustalev)
+- hesiod: use booleans in parser macro calls (Adhemerval Zanella)
+- hesiod: fix swapped arguments in service parser (Adhemerval Zanella)
+- math: Fix non-narrowing test build with arg-format conditions (Adhemerval Zanella)
+- aarch64: Use build attributes for asm feature marking (Muhammad Kamran)
+- misc: add a new test for gethostname (Martin Coufal)
+- test: Fix and stabilize tst-wcsmbs-clone-overflow test (Frédéric Bérat)
+- math: Fix fma alignment when exponent difference is exactly 64 (BZ 34183) (Adhemerval Zanella)
+
 * Thu May 28 2026 Frédéric Bérat <fberat@redhat.com> - 2.43.9000-18
 - Auto-sync with upstream branch master,
   commit b20b94006c79d65d75e5bd3a8d14fbcf9cd5bee6:

diff --git a/sources b/sources
index 3bfc80a..d8fe9f6 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-SHA512 (glibc-2.43.9000-364-gb20b94006c.tar.xz) = a7bd5efee6ccf7e97406c8505e7293fa5af7a59051256e77f86430dfce150947b388ab2426eee866901182b1a46a5dfad9e7fd7fd44ad7d768f153b7d8a0f27d
+SHA512 (glibc-2.43.9000-375-gc5278a6428.tar.xz) = 4df2b3c42293ca3365a7ad676d2ae338a74bfe0d7ac69b9c039ff5856c3ff1cdf3d42437e8260a74ab483ead18d21e81ee6b780afe54e377155c25df29d0230d

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-09-24 11:48 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-24 11:48 [rpms/glibc] rawhide: Auto-sync with upstream branch master 
  -- strict thread matches above, loose matches on Subject: below --
2026-07-21 17:07 
2026-07-07 13:52 
2026-06-23 17:32 
2026-06-16 13:09 
2026-06-10 15:23 
2026-06-02  7:31 

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox