LCOV - code coverage report
Current view: top level - lib - glob.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 11 37 29.7 %
Date: 2022-04-01 14:58:12 Functions: 1 1 100.0 %
Branches: 5 27 18.5 %

           Branch data     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                 :       3996 : 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                 :       3996 :         char const *back_pat = NULL, *back_str = 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                 :       4068 :         for (;;) {
      56                 :       4068 :                 unsigned char c = *str++;
      57                 :       4068 :                 unsigned char d = *pat++;
      58                 :            : 
      59   [ -  -  -  -  :       4068 :                 switch (d) {
                      + ]
      60                 :          0 :                 case '?':       /* Wildcard: anything but nul */
      61         [ #  # ]:          0 :                         if (c == '\0')
      62                 :            :                                 return false;
      63                 :            :                         break;
      64                 :          0 :                 case '*':       /* Any-length wildcard */
      65         [ #  # ]:          0 :                         if (*pat == '\0')       /* Optimize trailing * case */
      66                 :            :                                 return true;
      67                 :            :                         back_pat = pat;
      68                 :            :                         back_str = --str;       /* Allow zero-length match */
      69                 :            :                         break;
      70                 :          0 :                 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                 :          0 :                         do {
      81                 :          0 :                                 unsigned char b = a;
      82                 :            : 
      83         [ #  # ]:          0 :                                 if (a == '\0')  /* Malformed */
      84                 :          0 :                                         goto literal;
      85                 :            : 
      86   [ #  #  #  # ]:          0 :                                 if (class[0] == '-' && class[1] != ']') {
      87                 :          0 :                                         b = class[1];
      88                 :            : 
      89         [ #  # ]:          0 :                                         if (b == '\0')
      90                 :          0 :                                                 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                 :          0 :                                 goto backtrack;
     100                 :            :                         pat = class;
     101                 :            :                         }
     102                 :            :                         break;
     103                 :          0 :                 case '\\':
     104                 :          0 :                         d = *pat++;
     105                 :            :                         /*FALLTHROUGH*/
     106                 :            :                 default:        /* Literal character */
     107                 :       4068 : literal:
     108         [ +  + ]:       4068 :                         if (c == d) {
     109         [ +  - ]:         72 :                                 if (d == '\0')
     110                 :            :                                         return true;
     111                 :            :                                 break;
     112                 :            :                         }
     113                 :       3996 : backtrack:
     114         [ -  + ]:       3996 :                         if (c == '\0' || !back_pat)
     115                 :            :                                 return false;   /* No point continuing */
     116                 :            :                         /* Try again from last *, one character later in str. */
     117                 :          0 :                         pat = back_pat;
     118                 :          0 :                         str = ++back_str;
     119                 :          0 :                         break;
     120                 :            :                 }
     121                 :            :         }
     122                 :            : }
     123                 :            : EXPORT_SYMBOL(glob_match);

Generated by: LCOV version 1.14