Re: [PATCH 6/6] posix: Do not recurse once per pattern component in glob [BZ #34453]

Collin Funk <[email protected]>
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <[email protected]>
Adhemerval Zanella <[email protected]> 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 <[email protected]>

Collin

[1] https://github.com/coreutils/gnulib/commit/6edf6dbacf1e136539da03115adee858ec8a3d33
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.