From nobody Thu May 8 14:29:42 2025 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 4ZtZK26bjzz5v8w2; Thu, 08 May 2025 14:29:42 +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 "R11" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4ZtZK22Ylpz3HW4; Thu, 08 May 2025 14:29:42 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1746714582; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=P+q9cRD9bCOvHuEB63z2UQHMqJe5mH6wrrwk3pS8bw8=; b=w91UmyTJ6EKYpeU+w+DtE44VRMtGMjlc7p3B9KIFWaqzbYDMPrgZ9SJRxZqC4QpKNlMgLy SrjCKJMgJzQqwsnESA74zFwxe219nWPUWz7fcVWrfPKb6+gD+dHv6KjVFk2E5YkDFWDg90 z35oKRHtag66LHMYkbl3YECPXVGrBq48ElaUwvpVC8z/bhh5/3dQ6KSOI8exSacSyb+FRU MmPr0ooLOzoAJ+RZ2Squv4hUH+nSp3nxPOumzPsvblrkbnelh5eFMMUigOn11m9+yAg/wL ZeWJMMsLGeGhuuAnQDJ6vsz6I+MwsMXIreGMKGQoap13o9AqNMDoAMorsYXU6Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1746714582; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=P+q9cRD9bCOvHuEB63z2UQHMqJe5mH6wrrwk3pS8bw8=; b=DK2HvBRhj/Qh64xJI9zMupU63ZDruzuqaoIASGVsZ+CuwT+zpeXNLhMYZAUrt4CI1I+OYH hSlUxEyIR/3ojDbw7rl+u7OYrwJMoFqnklRIYX4zM4Ee8LkZ/wCsYcNuTER7O36j4joAxi qqK9EGw0kZ59OvdB15APziwy0xoYWxaaZs84eY0vfFKSOX0Ux4omOvewJ880IM9EwSXAeb mybqgM3apVyB7Vufv2g2uItRn4VXdOWK1VhU4cNSAGvXv/rFCl0LOQQ+2wmWySr9rsBPfz 9SQVxCfSxFZZGrPofbnRpnpHayA9XACumY2Pw7NUOXNXa/2a/J8Nqjvqh8alaw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1746714582; a=rsa-sha256; cv=none; b=iJPHLoe6fYdVCXVdo3e8SGbvWpoJmVKEKizAJM+VGdSrtWVONnVL/98a2JE0QeebswngQp AEs1SbGUyanBpj0EG9gEUxmQckseQuaYKfPXgI7uXiWN0PZls5YNzcQCXya99CdTXBgC2E /oQR0OL+r3QS2Emtj6WKruPNZyaxG3NTWCV3Ov/rRNXRURIDD1caPMpiAdgaNqHx8Oe+r9 hu3S1ZKr6bd8MPHTriKkkAgmdZvDOmSO97qdmxIveiJZlSvnrwNgsoyFWlTl8C7liNITvS OvK7fIZ9wvnrRbwiVHhs9MfZc5EfhPx3pjYWPTlGGh0xt7u3OmJdDz2htVXncA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (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 did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4ZtZK225HVz3bp; Thu, 08 May 2025 14:29:42 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 548ETgjN086594; Thu, 8 May 2025 14:29:42 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 548ETgL7086591; Thu, 8 May 2025 14:29:42 GMT (envelope-from git) Date: Thu, 8 May 2025 14:29:42 GMT Message-Id: <202505081429.548ETgL7086591@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Dag-Erling =?utf-8?Q?Sm=C3=B8rgrav?= Subject: git: da2025a0e894 - main - fts: Add FTS_COMFOLLOWDIR and FTS_NOSTAT_TYPE. 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 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: des X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: da2025a0e89455fb646b542b53d5a4ddaa2acbe0 Auto-Submitted: auto-generated The branch main has been updated by des: URL: https://cgit.FreeBSD.org/src/commit/?id=da2025a0e89455fb646b542b53d5a4ddaa2acbe0 commit da2025a0e89455fb646b542b53d5a4ddaa2acbe0 Author: Dag-Erling Smørgrav AuthorDate: 2025-05-08 14:28:51 +0000 Commit: Dag-Erling Smørgrav CommitDate: 2025-05-08 14:29:15 +0000 fts: Add FTS_COMFOLLOWDIR and FTS_NOSTAT_TYPE. MFC after: never Relnotes: yes Sponsored by: Klara, Inc. Reviewed by: kevans, imp Differential Revision: https://reviews.freebsd.org/D50233 --- include/fts.h | 6 +++++- lib/libc/gen/fts.3 | 22 +++++++++++++++++++++- lib/libc/gen/fts.c | 45 ++++++++++++++++++++++++++++++++++++++------- 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/include/fts.h b/include/fts.h index f2c40b854ffb..479905bda463 100644 --- a/include/fts.h +++ b/include/fts.h @@ -65,7 +65,11 @@ typedef struct { #define FTS_SEEDOT 0x000020 /* return dot and dot-dot */ #define FTS_XDEV 0x000040 /* don't cross devices */ #define FTS_WHITEOUT 0x000080 /* return whiteout information */ -#define FTS_OPTIONMASK 0x0000ff /* valid user option mask */ + /* 0x0100 is FTS_NAMEONLY below */ + /* 0x0200 was previously FTS_STOP */ +#define FTS_COMFOLLOWDIR 0x00400 /* like COMFOLLOW but directories only */ +#define FTS_NOSTAT_TYPE 0x000800 /* like NOSTAT but use d_type */ +#define FTS_OPTIONMASK 0x000cff /* valid user option mask */ /* valid only for fts_children() */ #define FTS_NAMEONLY 0x000100 /* child names only */ diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3 index 3007b773ec55..0c32bb0ebdb6 100644 --- a/lib/libc/gen/fts.3 +++ b/lib/libc/gen/fts.3 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 17, 2025 +.Dd May 7, 2025 .Dt FTS 3 .Os .Sh NAME @@ -394,6 +394,10 @@ This option causes any symbolic link specified as a root path to be followed immediately whether or not .Dv FTS_LOGICAL is also specified. +.It Dv FTS_COMFOLLOWDIR +This option is similar to +.Dv FTS_COMFOLLOW , +but only follows symbolic links to directories. .It Dv FTS_LOGICAL This option causes the .Nm @@ -449,6 +453,15 @@ field to and leave the contents of the .Fa statp field undefined. +.It Dv FTS_NOSTAT_TYPE +This option is similar to +.Dv FTS_NOSTAT , +but attempts to populate +.Fa fts_info +based on information from the +.Fa d_type +field of +.Vt struct dirent . .It Dv FTS_PHYSICAL This option causes the .Nm @@ -820,6 +833,13 @@ functions were introduced in principally to provide for alternative interfaces to the .Nm functionality using different data structures. +Blocks support and the +.Dv FTS_COMFOLLOWDIR +and +.Dv FTS_NOSTAT +options were added in +.Fx 15.0 +based on similar functionality in macOS. .Sh BUGS The .Fn fts_open diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c index a55b4a6e2981..fa3ee9cc4c83 100644 --- a/lib/libc/gen/fts.c +++ b/lib/libc/gen/fts.c @@ -126,6 +126,10 @@ __fts_open(FTS *sp, char * const *argv) if (ISSET(FTS_LOGICAL)) SET(FTS_NOCHDIR); + /* NOSTAT_TYPE implies NOSTAT */ + if (ISSET(FTS_NOSTAT_TYPE)) + SET(FTS_NOSTAT); + /* * Start out with 1K of path space, and enough, in any case, * to hold the user's paths. @@ -149,7 +153,9 @@ __fts_open(FTS *sp, char * const *argv) 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), -1); + p->fts_info = fts_stat(sp, p, + ISSET(FTS_COMFOLLOWDIR) ? -1 : ISSET(FTS_COMFOLLOW), + -1); /* Command-line "." and ".." are real directories. */ if (p->fts_info == FTS_DOT) @@ -904,6 +910,25 @@ mem1: saved_errno = errno; p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) --nlinks; } + if (p->fts_info == FTS_NSOK && ISSET(FTS_NOSTAT_TYPE)) { + switch (dp->d_type) { + case DT_FIFO: + case DT_CHR: + case DT_BLK: + case DT_SOCK: + p->fts_info = FTS_DEFAULT; + break; + case DT_REG: + p->fts_info = FTS_F; + break; + case DT_LNK: + p->fts_info = FTS_SL; + break; + case DT_WHT: + p->fts_info = FTS_W; + break; + } + } /* We walk in directory order so "ls -f" doesn't get upset. */ p->fts_link = NULL; @@ -980,7 +1005,7 @@ fts_stat(FTS *sp, FTSENT *p, int follow, int dfd) dev_t dev; ino_t ino; struct stat *sbp, sb; - int saved_errno; + int ret, saved_errno; const char *path; if (dfd == -1) { @@ -1003,19 +1028,25 @@ fts_stat(FTS *sp, FTSENT *p, int follow, int dfd) } /* - * 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 doing a logical walk, or caller requested FTS_COMFOLLOW, do + * a full stat(2). If that fails, do an lstat(2) to check for a + * non-existent symlink. If that fails, set the errno from the + * stat(2) call. + * + * As a special case, if stat(2) succeeded but the target is not a + * directory and follow is negative (indicating FTS_COMFOLLOWDIR + * rather than FTS_COMFOLLOW), we also revert to lstat(2). */ if (ISSET(FTS_LOGICAL) || follow) { - if (fstatat(dfd, path, sbp, 0)) { + if ((ret = fstatat(dfd, path, sbp, 0)) != 0 || + (follow < 0 && !S_ISDIR(sbp->st_mode))) { saved_errno = errno; if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { p->fts_errno = saved_errno; goto err; } errno = 0; - if (S_ISLNK(sbp->st_mode)) + if (ret != 0 && S_ISLNK(sbp->st_mode)) return (FTS_SLNONE); } } else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {