From nobody Sun Aug 16 21:03:22 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hNT2l42WQz6pbvB for ; Sun, 16 Aug 2026 21:03:27 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hNT2l21DRz3GSC for ; Sun, 16 Aug 2026 21:03:27 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786914207; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=fFWWL3IPel6OdSLyypGNcnJh7lFUMki6jZCD1XJbIYo=; b=sIUK1bki6mk59cMzAJLCTlnAowpbkUgQWZEWN7UHCQx1wf1hWO368ybXb1DgLvmykvVmaF VL55lpnsdyUmhU2FzZrhZvAopFwQBX9BBZi7JLuZmepHJ/LnC1g998GVY/WspZX8MSvjj+ x38eJNrJTp7pXeC+me2ftz2P9KJ0EZ12E5ddxe0TzXCPPYhVqEzBGnZGpWUnnUYWatWJ4t R0NWAErpDKTeIO+dMryAQukkovmb9hYLwoZ1O32C1zLTOpSmNiX4Wko3Mst0acIic3Jvl0 /83p0tI2g5DcTyP7+VoOcwU1RlutT325yXJq/cwRLNv/dh5CyHrh/KVLqphqgA== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1786914207; a=rsa-sha256; cv=none; b=GI8837JITjRSjgcjciz6Qll/OBMHnwhMMoKX7dlWWkkI/5hG6Hft2Uowa6rRiWtsclpX+I P41bAZoUVav8rn7SaZsBV9iOINRvg6AoJlWZJ/0YMQQrMIh+JiwT8QTeqT+R5EfSZ8NhL/ W6I55SS99sEkyeOHm+9qOeVBu7qpD6AKTpQpEsSMVY/Mahb6WNhJg9irCewn6dgoZzIBvN o1cWGTrXzUYDnmEjwFTvPd/Mh2ebBuBXEzQ53Hf8Viyd+Zrk9cPuIvTUf7w/7HDamtQBV/ tyjuECbWm+sSbZvCLBYezRDPdeMEziZoSI/XolRvT+Ax1K3tJnCIEn22/BqXow== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786914207; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=fFWWL3IPel6OdSLyypGNcnJh7lFUMki6jZCD1XJbIYo=; b=xPNbUhX+BPkbqpu7yp+pbmjDz5V64x8W1qB4xq9kfuVvEHsOBnkbQN7Fm+0qv8FZOIYW+y WUyJzp1I9tgriPEqbpZGQTPFGJ6+YazvbN8fIncf+Hdt1HFTvIloq7Nhx2/WXrZ6TNK6GR TXJpId+sRABOGiTli3cGvkAlel0k9MO97QKUkUHBy0TtgTZGfsd/dSw9/rktRmbIwwdoi1 k/kTIJGCzGyxai08nIEEbLWsl3RWPrIqqSSbv6czPa/K3iIpwR5gTwnpRjZBrT2RN6ZOqd QV4r7CLSaNd7L0cmLuH2qfSGS8AI7WAhYvEnj1K3fQ/77CVHmooqhMCOS4GYzw== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hNT2l0mvCzlJp for ; Sun, 16 Aug 2026 21:03:27 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 1be01 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sun, 16 Aug 2026 21:03:22 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Jitendra Bhati From: Alan Somers Subject: git: c1ff9c93b107 - main - fts: fix trailing-slash regression in fts_read after fts_children List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: asomers X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: c1ff9c93b107ef54b332bab114191e0a90ca84b7 Auto-Submitted: auto-generated Date: Sun, 16 Aug 2026 21:03:22 +0000 Message-Id: <6a82259a.1be01.29a4eb96@gitrepo.freebsd.org> The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=c1ff9c93b107ef54b332bab114191e0a90ca84b7 commit c1ff9c93b107ef54b332bab114191e0a90ca84b7 Author: Jitendra Bhati AuthorDate: 2026-08-15 15:03:56 +0000 Commit: Alan Somers CommitDate: 2026-08-16 21:02:43 +0000 fts: fix trailing-slash regression in fts_read after fts_children When fts_read() descends into a directory whose children were already prefetched by fts_children() (as ls -R does), it changed directory using p->fts_name instead of p->fts_accpath. With a trailing slash on a relative root path (e.g. 'dir/'), the bare name was resolved relative to the wrong directory, so every sibling directory after the first failed with ENOENT and was reported as FTS_DNR. This manifested as 'ls -lR dir/' skipping the contents of all but the first subdirectory. Restore the use of p->fts_accpath, matching the behavior prior to 4bd01d6ae016. Add a regression test that reproduces the exact conditions: fts_children() on each directory, FTS_PHYSICAL without FTS_NOCHDIR, and a trailing slash on the root path. Reported by: Michael Butler Reviewed by: asomers Fixes: 4bd01d6ae016 Sponsored by: Google LLC (GSoC 2026) Pull Request: https://github.com/freebsd/freebsd-src/pull/2372 --- lib/libc/gen/fts.c | 2 +- lib/libc/tests/gen/fts_regress_test.c | 58 +++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index e388fce550b9..96741dab8beb 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -489,7 +489,7 @@ fts_read(FTS *sp) * FTS_STOP or the fts_info field of the node. */ if (sp->fts_child != NULL) { - if (fts_safe_changedir(sp, p, -1, p->fts_name)) { + 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; diff --git a/lib/libc/tests/gen/fts_regress_test.c b/lib/libc/tests/gen/fts_regress_test.c index 7075addf92b4..57a29e7f1ec8 100644 --- a/lib/libc/tests/gen/fts_regress_test.c +++ b/lib/libc/tests/gen/fts_regress_test.c @@ -362,6 +362,63 @@ ATF_TC_BODY(accpath_correct_after_descent, tc) ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m"); } +ATF_TC(trailing_slash_children); +ATF_TC_HEAD(trailing_slash_children, tc) +{ + atf_tc_set_md_var(tc, "descr", + "fts_children() works for all siblings when the root path " + "has a trailing slash and FTS_NOCHDIR is not set"); +} +ATF_TC_BODY(trailing_slash_children, tc) +{ + char *paths[] = { "root/", NULL }; + FTS *fts; + FTSENT *ent, *children; + int files_seen = 0; + + /* + * Reproduce the bug reported on freebsd-current: "ls -lR dir/" + * (trailing slash, relative path) skipped the contents of all + * subdirectories after the first. It requires fts_children() + * to be called on each directory (as ls -R does), FTS_PHYSICAL + * without FTS_NOCHDIR, and a trailing slash on the root path. + * + * The root cause was that fts_read() descended into each + * subdirectory using fts_safe_changedir(sp, p, -1, p->fts_name) + * instead of p->fts_accpath. With a trailing-slash root, the + * bare name was resolved relative to the wrong directory, so + * every sibling after the first failed with ENOENT and was + * reported as FTS_DNR. + */ + ATF_REQUIRE_EQ(0, mkdir("root", 0755)); + ATF_REQUIRE_EQ(0, mkdir("root/sub1", 0755)); + ATF_REQUIRE_EQ(0, mkdir("root/sub2", 0755)); + ATF_REQUIRE_EQ(0, mkdir("root/sub3", 0755)); + ATF_REQUIRE_EQ(0, close(creat("root/sub1/file1", 0644))); + ATF_REQUIRE_EQ(0, close(creat("root/sub2/file2", 0644))); + ATF_REQUIRE_EQ(0, close(creat("root/sub3/file3", 0644))); + + ATF_REQUIRE((fts = fts_open(paths, FTS_PHYSICAL, NULL)) != NULL); + + while ((ent = fts_read(fts)) != NULL) { + if (ent->fts_info == FTS_D) { + children = fts_children(fts, 0); + (void)children; + } + if (ent->fts_info == FTS_DNR || ent->fts_info == FTS_ERR) + atf_tc_fail("fts entry '%s' returned info=%d " + "errno=%d — subdirectory contents skipped", + ent->fts_name, ent->fts_info, ent->fts_errno); + if (ent->fts_info == FTS_F) + files_seen++; + } + + ATF_CHECK_EQ_MSG(3, files_seen, + "expected to visit 3 files, saw %d — sibling directories " + "were skipped after the first", files_seen); + ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m"); +} + ATF_TP_ADD_TCS(tp) { ATF_TP_ADD_TC(tp, read_no_exec_dir); @@ -370,6 +427,7 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, odirectory_changedir); ATF_TP_ADD_TC(tp, concurrent_modification); ATF_TP_ADD_TC(tp, accpath_correct_after_descent); + ATF_TP_ADD_TC(tp, trailing_slash_children); return (atf_no_error()); }