=freebsd.org; s=dkim; t=1748856795; 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=ckVQY4Ah0Q8o0zZNHZzfD/XpitPMfSdkk+8aGU8o3nE=; b=PzSpRmYMKbrhk9vkUq4r7aNRYWADORYA6IJUCvtTemHchNW9jezCAYdCzMYs96Bm6O/cHu 8XQ2K0mx2xKJEu8o00cVadPLA7/0Nk3Q9jBam7a8FJkb9nqGVOb95YORnZLkqc5h8xahNZ yBFP3sN/W92S53IZbrE45PkdzVVMEXOd9c9WTgu1bIr9q14bPG3cj/Vco/xegLgJB87SXE wbLoKWfKNhuufmXo9grHpECLufNy+fxA/usW3D1n/XNNX0wtQpdgkNSuUZcdj80uKDY0fN iRJOnA8b/8Lhn6+ezLrlqVPpzdfCijuno8uAHB6swVfQZW33VaGdYc8UrR36Kg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1748856795; a=rsa-sha256; cv=none; b=DqA9brA5LDmcbxJNQSDS1nwsia4C3NixX6d3g+B0SVlti+wHN7Lj4Au3Hr/Na1iyCZjDib d/e7tQlwy/Buq1MiyntSC9FrS/hHNnWSaQdJf6jjoCKkOzoiB/4lUhU4hTvNpndVcJlQYu CbvcgruDa88qjD1PTfBax09UOe7s9wnR40zjBs6dgRbyd5+ruAePlTE+AyIM5bmii6U2mR tc8+QNyouLBTjDffjyUkfmerjJu4RjfyZaRZvdwAl9TKewOgTBZLRtHMopm9qXbcxnFSY2 SPzoAEpRx7u96kHeabKOx6zU8oVyWSjgNPwbvB7lZWmRaK03b164VbUW7ux22g== 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 4b9pYR0BxBz13TN; Mon, 02 Jun 2025 09:33:15 +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 5529XEOO083104; Mon, 2 Jun 2025 09:33:14 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 5529XEpk083101; Mon, 2 Jun 2025 09:33:14 GMT (envelope-from git) Date: Mon, 2 Jun 2025 09:33:14 GMT Message-Id: <202506020933.5529XEpk083101@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Bojan =?utf-8?Q?Novkovi=C4=87?= Subject: git: 1e0743f54d2d - main - glob: Add blocks support 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: bnovkov X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 1e0743f54d2d3624cd4de2167d373aa38597778e Auto-Submitted: auto-generated The branch main has been updated by bnovkov: URL: https://cgit.FreeBSD.org/src/commit/?id=1e0743f54d2d3624cd4de2167d373aa38597778e commit 1e0743f54d2d3624cd4de2167d373aa38597778e Author: Bojan Novković AuthorDate: 2025-05-23 13:26:04 +0000 Commit: Bojan Novković CommitDate: 2025-06-02 09:32:50 +0000 glob: Add blocks support This change introduces the `glob_b` function which takes a block instead of a function pointer. Relnotes: yes Sponsored by: Klara, Inc. Inspired by: https://github.com/apple-oss-distributions/Libc Differential Revision: https://reviews.freebsd.org/D50485 --- include/glob.h | 16 +++++++++-- lib/libc/gen/Makefile.inc | 1 + lib/libc/gen/Symbol.map | 1 + lib/libc/gen/glob.3 | 66 ++++++++++++++++++++++++++++++++++++++------ lib/libc/gen/glob.c | 70 +++++++++++++++++++++++++++++++++++++---------- 5 files changed, 128 insertions(+), 26 deletions(-) diff --git a/include/glob.h b/include/glob.h index dc86cdf99929..cbe99bfef6ed 100644 --- a/include/glob.h +++ b/include/glob.h @@ -50,8 +50,15 @@ typedef struct { size_t gl_offs; /* Reserved at beginning of gl_pathv. */ int gl_flags; /* Copy of flags parameter to glob. */ char **gl_pathv; /* List of paths matching pattern. */ - /* Copy of errfunc parameter to glob. */ - int (*gl_errfunc)(const char *, int); + /* Copy of error callback parameter to glob. */ + union { + int (*gl_errfunc)(const char *, int); +#ifdef __BLOCKS__ + int (^gl_errblk)(const char *, int); +#else + void *gl_errblk; +#endif + }; /* * Alternate filesystem access methods for glob; replacement @@ -90,6 +97,7 @@ typedef struct { #define GLOB_QUOTE 0x0400 /* Quote special chars with \. */ #define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */ #define GLOB_LIMIT 0x1000 /* limit number of returned paths */ +#define _GLOB_ERR_BLOCK 0x08000000 /* (internal) error callback is a block */ /* source compatibility, these are the old names */ #define GLOB_MAXPATH GLOB_LIMIT @@ -99,6 +107,10 @@ typedef struct { __BEGIN_DECLS int glob(const char * __restrict, int, int (*)(const char *, int), glob_t * __restrict); +#ifdef __BLOCKS__ +int glob_b(const char * __restrict, int, + int (^)(const char *, int), glob_t * __restrict); +#endif void globfree(glob_t *); __END_DECLS diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 302fd3a004d1..74b18b44e575 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -172,6 +172,7 @@ SRCS+= \ .if ${COMPILER_FEATURES:Mblocks} CFLAGS.fts.c= -fblocks +CFLAGS.glob.c= -fblocks .endif CFLAGS.arc4random.c= -I${SRCTOP}/sys -I${SRCTOP}/sys/crypto/chacha20 diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 2ddca1f20e00..afc277822787 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -459,6 +459,7 @@ FBSD_1.8 { aio_write2; execvpe; fts_open_b; + glob_b; psiginfo; rtld_get_var; rtld_set_var; diff --git a/lib/libc/gen/glob.3 b/lib/libc/gen/glob.3 index 006e8decb3db..9f15b2edb63a 100644 --- a/lib/libc/gen/glob.3 +++ b/lib/libc/gen/glob.3 @@ -27,11 +27,12 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd December 20, 2011 +.Dd June 02, 2025 .Dt GLOB 3 .Os .Sh NAME .Nm glob , +.Nm glob_b, .Nm globfree .Nd generate pathnames matching a pattern .Sh LIBRARY @@ -39,7 +40,9 @@ .Sh SYNOPSIS .In glob.h .Ft int -.Fn glob "const char * restrict pattern" "int flags" "int (*errfunc)(const char *, int)" "glob_t * restrict pglob" +.Fn glob "const char * restrict pattern" "int flags" "int (*errfunc)(const char *epath, int errno)" "glob_t * restrict pglob" +.Ft int +.Fn glob_b "const char * restrict pattern" "int flags" "int (^errblk)(const char *epath, int errno)" "glob_t * restrict pglob" .Ft void .Fn globfree "glob_t *pglob" .Sh DESCRIPTION @@ -272,10 +275,24 @@ is .Pf non- Dv NULL , .Fn glob calls -.Fa \*(lp*errfunc\*(rp Ns ( Fa path , errno ) , +.Fa \*(lp*errfunc\*(rp Ns ( Fa path , errno ) . +This may be unintuitive: a pattern like +.Ql */Makefile +will try to +.Xr stat 2 +.Ql foo/Makefile +even if +.Ql foo +is not a directory, resulting in a +call to +.Fa errfunc . +The error routine can suppress this action by testing for +.Er ENOENT +and +.Er ENOTDIR ; however, the .Dv GLOB_ERR -flag will cause an immediate +flag will still cause an immediate return when this happens. .Pp If @@ -307,16 +324,27 @@ or returns zero, the error is ignored. .Pp The +.Fn glob_b +function is like +.Fn glob +except that the error callback is a block pointer instead of a function +pointer. +.Pp +The .Fn globfree function frees any space associated with .Fa pglob from a previous call(s) to -.Fn glob . +.Fn glob +or +.Fn glob_b . .Sh RETURN VALUES On successful completion, .Fn glob -returns zero. -In addition the fields of +and +.Fn glob_b +return zero. +In addition, the fields of .Fa pglob contain the values described below: .Bl -tag -width GLOB_NOCHECK @@ -324,12 +352,16 @@ contain the values described below: contains the total number of matched pathnames so far. This includes other matches from previous invocations of .Fn glob +or +.Fn glob_b . if .Dv GLOB_APPEND was specified. .It Fa gl_matchc contains the number of matched pathnames in the current invocation of -.Fn glob . +.Fn glob +or +.Fn glob_b . .It Fa gl_flags contains a copy of the .Fa flags @@ -352,6 +384,8 @@ are undefined. .Pp If .Fn glob +or +.Fn glob_b terminates due to an error, it sets errno and returns one of the following non-zero constants, which are defined in the include file @@ -397,6 +431,14 @@ g.gl_pathv[0] = "ls"; g.gl_pathv[1] = "-l"; execvp("ls", g.gl_pathv); .Ed +.Sh CAVEATS +The +.Fn glob +and +.Fn glob_b +functions +will not match filenames that begin with a period +unless this is specifically requested (e.g., by ".*"). .Sh SEE ALSO .Xr sh 1 , .Xr fnmatch 3 , @@ -435,6 +477,10 @@ and .Fn globfree functions first appeared in .Bx 4.4 . +The +.Fn glob_b +function first appeared in +.Fx 15.0 . .Sh BUGS Patterns longer than .Dv MAXPATHLEN @@ -442,7 +488,9 @@ may cause unchecked errors. .Pp The .Fn glob -argument +and +.Fn glob_b +functions may fail and set errno for any of the errors specified for the library routines .Xr stat 2 , diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c index 7a988196549a..1ac919edaa12 100644 --- a/lib/libc/gen/glob.c +++ b/lib/libc/gen/glob.c @@ -88,8 +88,11 @@ #include #include +#include "block_abi.h" #include "collate.h" +typedef DECLARE_BLOCK(int, glob_b_block, const char*, int); + /* * glob(3) expansion limits. Stop the expansion if any of these limits * is reached. This caps the runtime in the face of DoS attacks. See @@ -179,9 +182,8 @@ static int err_aborted(glob_t *, int, char *); static void qprintf(const char *, Char *); #endif -int -glob(const char * __restrict pattern, int flags, - int (*errfunc)(const char *, int), glob_t * __restrict pglob) +static int +__glob(const char *pattern, glob_t *pglob) { struct glob_limit limit = { 0, 0, 0, 0, 0 }; const char *patnext; @@ -192,25 +194,23 @@ glob(const char * __restrict pattern, int flags, int too_long; patnext = pattern; - if (!(flags & GLOB_APPEND)) { + if (!(pglob->gl_flags & GLOB_APPEND)) { pglob->gl_pathc = 0; pglob->gl_pathv = NULL; - if (!(flags & GLOB_DOOFFS)) + if (!(pglob->gl_flags & GLOB_DOOFFS)) pglob->gl_offs = 0; } - if (flags & GLOB_LIMIT) { + if (pglob->gl_flags & GLOB_LIMIT) { limit.l_path_lim = pglob->gl_matchc; if (limit.l_path_lim == 0) limit.l_path_lim = GLOB_LIMIT_PATH; } - pglob->gl_flags = flags & ~GLOB_MAGCHAR; - pglob->gl_errfunc = errfunc; pglob->gl_matchc = 0; bufnext = patbuf; bufend = bufnext + MAXPATHLEN - 1; too_long = 1; - if (flags & GLOB_NOESCAPE) { + if (pglob->gl_flags & GLOB_NOESCAPE) { memset(&mbs, 0, sizeof(mbs)); while (bufnext <= bufend) { clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); @@ -250,15 +250,45 @@ glob(const char * __restrict pattern, int flags, return (err_nomatch(pglob, &limit, pattern)); *bufnext = EOS; - if (flags & GLOB_BRACE) + if (pglob->gl_flags & GLOB_BRACE) return (globexp0(patbuf, pglob, &limit, pattern)); else return (glob0(patbuf, pglob, &limit, pattern)); } +int +glob(const char * __restrict pattern, int flags, + int (*errfunc)(const char *, int), glob_t * __restrict pglob) +{ + int rv; + + pglob->gl_flags = flags & ~(GLOB_MAGCHAR | _GLOB_ERR_BLOCK); + pglob->gl_errfunc = errfunc; + rv = __glob(pattern, pglob); + pglob->gl_errfunc = NULL; + + return (rv); +} + +int +glob_b(const char * __restrict pattern, int flags, + glob_b_block block, glob_t * __restrict pglob) +{ + int rv; + + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_flags |= _GLOB_ERR_BLOCK; + pglob->gl_errblk = block; + rv = __glob(pattern, pglob); + pglob->gl_errblk = NULL; + + return (rv); +} + static int globexp0(const Char *pattern, glob_t *pglob, struct glob_limit *limit, - const char *origpat) { + const char *origpat) +{ int rv; size_t oldpathc; @@ -724,7 +754,7 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last, return (GLOB_NOSPACE); } *pathend = EOS; - if (pglob->gl_errfunc != NULL && + if ((pglob->gl_errfunc != NULL || pglob->gl_errblk != NULL) && g_Ctoc(pathbuf, buf, sizeof(buf))) { errno = E2BIG; return (GLOB_NOSPACE); @@ -1085,10 +1115,20 @@ err_nomatch(glob_t *pglob, struct glob_limit *limit, const char *origpat) { } static int -err_aborted(glob_t *pglob, int err, char *buf) { - if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) || - (pglob->gl_flags & GLOB_ERR)) +err_aborted(glob_t *pglob, int err, char *buf) +{ + int rv = 0; + + if ((pglob->gl_flags & _GLOB_ERR_BLOCK) != 0) { + if (pglob->gl_errblk != NULL) + rv = CALL_BLOCK(pglob->gl_errblk, buf, errno); + } else if (pglob->gl_errfunc != NULL) { + rv = pglob->gl_errfunc(buf, errno); + } + /* GLOB_ERR is allowed to override the error callback function. */ + if (rv != 0 || pglob->gl_flags & GLOB_ERR) { return (GLOB_ABORTED); + } return (0); }