mirror of
https://git.freebsd.org/src.git
synced 2026-01-16 23:02:24 +00:00
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
This commit is contained in:
parent
61d77e6c00
commit
1e0743f54d
5 changed files with 128 additions and 26 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -459,6 +459,7 @@ FBSD_1.8 {
|
|||
aio_write2;
|
||||
execvpe;
|
||||
fts_open_b;
|
||||
glob_b;
|
||||
psiginfo;
|
||||
rtld_get_var;
|
||||
rtld_set_var;
|
||||
|
|
|
|||
|
|
@ -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 ,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue