[PATCH 6/6] posix: Do not recurse once per pattern component in glob [BZ #34453]
Collin Funk
collin.funk1@gmail.com
Sat Aug 8 05:52:22 GMT 2026
Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
> +/* Remove one unquoted trailing backslash from P, which is *LENP bytes long,
> + and update *LENP. */
> +static void
> +glob_strip_backslash (char *p, size_t *lenp)
> +{
> + size_t len = *lenp;
> + char *q = &p[len - 1];
> +
> + while (q > p && q[-1] == '\\')
> + --q;
> + /* Check if the number of '\' is odd. */
> + if ((&p[len] - q) & 1)
> + p[--len] = '\0';
> + *lenp = len;
> +}
> +
> +/* Remove the quoting backslashes from P, which is *LENP bytes long and
> + contains at least one backslash, and update *LENP. */
> +static void
> +glob_unescape (char *p, size_t *lenp)
> +{
> + size_t len = *lenp;
> + char *s = strchr (p, '\\');
> + char *d = s;
Since we have LEN, can't we use memchr? Not that P will be long enough
to matter much, of course.
> + do
> + {
> + if (*s == '\\')
> + {
> + *d = *++s;
> + --len;
> + }
> + else
> + *d = *s;
> + ++d;
> + }
> + while (*s++ != '\0');
> + *lenp = len;
> +}
I think it would be better for glob_strip_backslash and glob_unescape
should return LEN instead of modifying a pointer. Any reason why they
shouldn't?
These functions are small, so it isn't a major issue, but I find it
easier to forget to set a pointer in one path than to forget a return.
> +/* Expand DIRPATTERN, the directory part of a pattern, into PGLOB. FLAGS
> + holds GLOB_ERR, GLOB_NOESCAPE and GLOB_ALTDIRFUNC as inherited from the
> + caller, plus GLOB_NOSORT and GLOB_ONLYDIR.
> +
> + DIRPATTERN is split at its slashes into components, each recorded in a
> + heap-allocated array along with what it has to do with the directories
> + it matches. The components are then matched from left to right,
> + starting at the longest leading part that has no metacharacter. Stack
> + usage does not depend on how many components there are, and a component
> + that matches nothing ends the expansion at once. */
> +static int
> +glob_dir_pattern (const char *dirpattern, int flags,
> + int (*errfunc) (const char *, int), glob_t *pglob)
> +{
> + bool quote = !(flags & GLOB_NOESCAPE);
> + struct glob_dir_step *steps = NULL;
> + size_t nsteps = 0;
> + size_t maxsteps;
> + char *work;
> + char *p;
> + const char *base;
> + const char *base_pattern;
> + size_t baselen;
> + /* Whether the level being scanned appends slashes to its result. A
> + component followed by a slash passes this down instead of matching
> + anything itself, exactly as GLOB_MARK is passed down by glob. */
> + bool mark = false;
> + glob_t cur;
> + int retval;
> +
> + /* The pattern is split in place, so work on a copy. */
> + work = strdup (dirpattern);
> + if (work == NULL)
> + return GLOB_NOSPACE;
> + p = work;
> +
> + /* Every step splits the pattern at a slash, so there is never more than one
> + step per slash. */
> + maxsteps = glob_count (dirpattern, '/');
I will probably need to reduce the variable scope here and some other
places before importing it to gnulib. But I think it is okay for now.
There is already a large diff in what gnulib and glibc have since
Bruno's reduction of variable scope last year [1].
Generally, the patch looks good though. I tested them in gnulib and it
passes those tests on GNU/Linux.
Anyway, I don't think the minor points I brought up require a V2. Feel
free to add my Reviewed-by after checking them, whether you decide to
make the changes or not.
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
Collin
[1] https://github.com/coreutils/gnulib/commit/6edf6dbacf1e136539da03115adee858ec8a3d33
More information about the Libc-alpha
mailing list