LCOV - code coverage report
Current view: top level - lib - glob.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 12 26 46.2 %
Date: 2023-08-24 13:40:31 Functions: 1 1 100.0 %

          Line data    Source code
       1             : #include <linux/module.h>
       2             : #include <linux/glob.h>
       3             : 
       4             : /*
       5             :  * The only reason this code can be compiled as a module is because the
       6             :  * ATA code that depends on it can be as well.  In practice, they're
       7             :  * both usually compiled in and the module overhead goes away.
       8             :  */
       9             : MODULE_DESCRIPTION("glob(7) matching");
      10             : MODULE_LICENSE("Dual MIT/GPL");
      11             : 
      12             : /**
      13             :  * glob_match - Shell-style pattern matching, like !fnmatch(pat, str, 0)
      14             :  * @pat: Shell-style pattern to match, e.g. "*.[ch]".
      15             :  * @str: String to match.  The pattern must match the entire string.
      16             :  *
      17             :  * Perform shell-style glob matching, returning true (1) if the match
      18             :  * succeeds, or false (0) if it fails.  Equivalent to !fnmatch(@pat, @str, 0).
      19             :  *
      20             :  * Pattern metacharacters are ?, *, [ and \.
      21             :  * (And, inside character classes, !, - and ].)
      22             :  *
      23             :  * This is small and simple implementation intended for device blacklists
      24             :  * where a string is matched against a number of patterns.  Thus, it
      25             :  * does not preprocess the patterns.  It is non-recursive, and run-time
      26             :  * is at most quadratic: strlen(@str)*strlen(@pat).
      27             :  *
      28             :  * An example of the worst case is glob_match("*aaaaa", "aaaaaaaaaa");
      29             :  * it takes 6 passes over the pattern before matching the string.
      30             :  *
      31             :  * Like !fnmatch(@pat, @str, 0) and unlike the shell, this does NOT
      32             :  * treat / or leading . specially; it isn't actually used for pathnames.
      33             :  *
      34             :  * Note that according to glob(7) (and unlike bash), character classes
      35             :  * are complemented by a leading !; this does not support the regex-style
      36             :  * [^a-z] syntax.
      37             :  *
      38             :  * An opening bracket without a matching close is matched literally.
      39             :  */
      40          16 : bool __pure glob_match(char const *pat, char const *str)
      41             : {
      42             :         /*
      43             :          * Backtrack to previous * on mismatch and retry starting one
      44             :          * character later in the string.  Because * matches all characters
      45             :          * (no exception for /), it can be easily proved that there's
      46             :          * never a need to backtrack multiple levels.
      47             :          */
      48          16 :         char const *back_pat = NULL, *back_str;
      49             : 
      50             :         /*
      51             :          * Loop over each token (character or class) in pat, matching
      52             :          * it against the remaining unmatched tail of str.  Return false
      53             :          * on mismatch, or true after matching the trailing nul bytes.
      54             :          */
      55             :         for (;;) {
      56         352 :                 unsigned char c = *str++;
      57         352 :                 unsigned char d = *pat++;
      58             : 
      59         352 :                 switch (d) {
      60             :                 case '?':       /* Wildcard: anything but nul */
      61           0 :                         if (c == '\0')
      62             :                                 return false;
      63             :                         break;
      64             :                 case '*':       /* Any-length wildcard */
      65          17 :                         if (*pat == '\0')       /* Optimize trailing * case */
      66             :                                 return true;
      67             :                         back_pat = pat;
      68             :                         back_str = --str;       /* Allow zero-length match */
      69             :                         break;
      70             :                 case '[': {     /* Character class */
      71           0 :                         bool match = false, inverted = (*pat == '!');
      72           0 :                         char const *class = pat + inverted;
      73           0 :                         unsigned char a = *class++;
      74             : 
      75             :                         /*
      76             :                          * Iterate over each span in the character class.
      77             :                          * A span is either a single character a, or a
      78             :                          * range a-b.  The first span may begin with ']'.
      79             :                          */
      80             :                         do {
      81           0 :                                 unsigned char b = a;
      82             : 
      83           0 :                                 if (a == '\0')  /* Malformed */
      84             :                                         goto literal;
      85             : 
      86           0 :                                 if (class[0] == '-' && class[1] != ']') {
      87           0 :                                         b = class[1];
      88             : 
      89           0 :                                         if (b == '\0')
      90             :                                                 goto literal;
      91             : 
      92           0 :                                         class += 2;
      93             :                                         /* Any special action if a > b? */
      94             :                                 }
      95           0 :                                 match |= (a <= c && c <= b);
      96           0 :                         } while ((a = *class++) != ']');
      97             : 
      98           0 :                         if (match == inverted)
      99             :                                 goto backtrack;
     100             :                         pat = class;
     101             :                         }
     102             :                         break;
     103             :                 case '\\':
     104           0 :                         d = *pat++;
     105             :                         fallthrough;
     106             :                 default:        /* Literal character */
     107             : literal:
     108         335 :                         if (c == d) {
     109          93 :                                 if (d == '\0')
     110             :                                         return true;
     111             :                                 break;
     112             :                         }
     113             : backtrack:
     114         242 :                         if (c == '\0' || !back_pat)
     115             :                                 return false;   /* No point continuing */
     116             :                         /* Try again from last *, one character later in str. */
     117         227 :                         pat = back_pat;
     118         227 :                         str = ++back_str;
     119         227 :                         break;
     120             :                 }
     121             :         }
     122             : }
     123             : EXPORT_SYMBOL(glob_match);

Generated by: LCOV version 1.14