Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 2 Jun 2025 09:33:14 GMT
From:      Bojan =?utf-8?Q?Novkovi=C4=87?= <bnovkov@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 1e0743f54d2d - main - glob: Add blocks support
Message-ID:  <202506020933.5529XEpk083101@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by bnovkov:

URL: https://cgit.FreeBSD.org/src/commit/?id=1e0743f54d2d3624cd4de2167d373aa38597778e

commit 1e0743f54d2d3624cd4de2167d373aa38597778e
Author:     Bojan Novković <bnovkov@FreeBSD.org>
AuthorDate: 2025-05-23 13:26:04 +0000
Commit:     Bojan Novković <bnovkov@FreeBSD.org>
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 <unistd.h>
 #include <wchar.h>
 
+#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);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202506020933.5529XEpk083101>