LCOV - code coverage report
Current view: top level - source3/lib - ms_fnmatch.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 62 111 55.9 %
Date: 2024-04-21 15:09:00 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    filename matching routine
       4             :    Copyright (C) Andrew Tridgell 1992-2004
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : /*
      21             :    This module was originally based on fnmatch.c copyright by the Free
      22             :    Software Foundation. It bears little (if any) resemblance to that
      23             :    code now
      24             : */
      25             : 
      26             : 
      27             : #include "includes.h"
      28             : 
      29       24155 : static int null_match(const smb_ucs2_t *p)
      30             : {
      31       24155 :         for (;*p;p++) {
      32           0 :                 if (*p != UCS2_CHAR('*') &&
      33           0 :                     *p != UCS2_CHAR('<') &&
      34           0 :                     *p != UCS2_CHAR('"') &&
      35           0 :                     *p != UCS2_CHAR('>')) return -1;
      36             :         }
      37       24155 :         return 0;
      38             : }
      39             : 
      40             : /*
      41             :   the max_n structure is purely for efficiency, it doesn't contribute
      42             :   to the matching algorithm except by ensuring that the algorithm does
      43             :   not grow exponentially
      44             : */
      45             : struct max_n {
      46             :         const smb_ucs2_t *predot;
      47             :         const smb_ucs2_t *postdot;
      48             : };
      49             : 
      50             : 
      51             : /*
      52             :   p and n are the pattern and string being matched. The max_n array is
      53             :   an optimisation only. The ldot pointer is NULL if the string does
      54             :   not contain a '.', otherwise it points at the last dot in 'n'.
      55             : */
      56      124891 : static int ms_fnmatch_core(const smb_ucs2_t *p, const smb_ucs2_t *n,
      57             :                            struct max_n *max_n, const smb_ucs2_t *ldot,
      58             :                            bool is_case_sensitive)
      59             : {
      60           0 :         smb_ucs2_t c;
      61           0 :         int i;
      62             : 
      63      127771 :         while ((c = *p++)) {
      64       32555 :                 switch (c) {
      65             :                         /* a '*' matches zero or more characters of any type */
      66       24155 :                 case UCS2_CHAR('*'):
      67       24155 :                         if (max_n->predot && max_n->predot <= n) {
      68           0 :                                 return null_match(p);
      69             :                         }
      70      118891 :                         for (i=0; n[i]; i++) {
      71       94736 :                                 if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) {
      72           0 :                                         return 0;
      73             :                                 }
      74             :                         }
      75       24155 :                         if (!max_n->predot || max_n->predot > n) max_n->predot = n;
      76       24155 :                         return null_match(p);
      77             : 
      78             :                         /* a '<' matches zero or more characters of
      79             :                            any type, but stops matching at the last
      80             :                            '.' in the string. */
      81        1440 :                 case UCS2_CHAR('<'):
      82        1440 :                         if (max_n->predot && max_n->predot <= n) {
      83           0 :                                 return null_match(p);
      84             :                         }
      85        1440 :                         if (max_n->postdot && max_n->postdot <= n && n <= ldot) {
      86           0 :                                 return -1;
      87             :                         }
      88        3600 :                         for (i=0; n[i]; i++) {
      89        3600 :                                 if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) return 0;
      90        3120 :                                 if (n+i == ldot) {
      91         960 :                                         if (ms_fnmatch_core(p, n+i+1, max_n+1, ldot, is_case_sensitive) == 0) return 0;
      92         960 :                                         if (!max_n->postdot || max_n->postdot > n) max_n->postdot = n;
      93         960 :                                         return -1;
      94             :                                 }
      95             :                         }
      96           0 :                         if (!max_n->predot || max_n->predot > n) max_n->predot = n;
      97           0 :                         return null_match(p);
      98             : 
      99             :                         /* a '?' matches any single character */
     100           0 :                 case UCS2_CHAR('?'):
     101           0 :                         if (! *n) {
     102           0 :                                 return -1;
     103             :                         }
     104           0 :                         n++;
     105           0 :                         break;
     106             : 
     107             :                         /* a '?' matches any single character */
     108           0 :                 case UCS2_CHAR('>'):
     109           0 :                         if (n[0] == UCS2_CHAR('.')) {
     110           0 :                                 if (! n[1] && null_match(p) == 0) {
     111           0 :                                         return 0;
     112             :                                 }
     113           0 :                                 break;
     114             :                         }
     115           0 :                         if (! *n) return null_match(p);
     116           0 :                         n++;
     117           0 :                         break;
     118             : 
     119           0 :                 case UCS2_CHAR('"'):
     120           0 :                         if (*n == 0 && null_match(p) == 0) {
     121           0 :                                 return 0;
     122             :                         }
     123           0 :                         if (*n != UCS2_CHAR('.')) return -1;
     124           0 :                         n++;
     125           0 :                         break;
     126             : 
     127        6960 :                 default:
     128        6960 :                         if (c != *n) {
     129        4080 :                                 if (is_case_sensitive) {
     130           0 :                                         return -1;
     131             :                                 }
     132        4080 :                                 if (toupper_w(c) != toupper_w(*n)) {
     133        4080 :                                         return -1;
     134             :                                 }
     135             :                         }
     136        2880 :                         n++;
     137        2880 :                         break;
     138             :                 }
     139             :         }
     140             : 
     141       95216 :         if (! *n) {
     142         480 :                 return 0;
     143             :         }
     144             : 
     145       94736 :         return -1;
     146             : }
     147             : 
     148       25613 : int ms_fnmatch(const char *pattern, const char *string, bool translate_pattern,
     149             :                bool is_case_sensitive)
     150             : {
     151       25613 :         smb_ucs2_t *p = NULL;
     152       25613 :         smb_ucs2_t *s = NULL;
     153           0 :         int ret;
     154           0 :         size_t count, i;
     155       25613 :         struct max_n *max_n = NULL;
     156       25613 :         struct max_n *max_n_free = NULL;
     157           0 :         struct max_n one_max_n;
     158           0 :         size_t converted_size;
     159             : 
     160       25613 :         if (ISDOTDOT(string)) {
     161           0 :                 string = ".";
     162             :         }
     163             : 
     164       25613 :         if (strpbrk(pattern, "<>*?\"") == NULL) {
     165             :                 /* this is not just an optimisation - it is essential
     166             :                    for LANMAN1 correctness */
     167          18 :                 if (is_case_sensitive) {
     168           0 :                         return strcmp(pattern, string);
     169             :                 } else {
     170          18 :                         return strcasecmp_m(pattern, string);
     171             :                 }
     172             :         }
     173             : 
     174       25595 :         if (!push_ucs2_talloc(talloc_tos(), &p, pattern, &converted_size)) {
     175           0 :                 return -1;
     176             :         }
     177             : 
     178       25595 :         if (!push_ucs2_talloc(talloc_tos(), &s, string, &converted_size)) {
     179           0 :                 TALLOC_FREE(p);
     180           0 :                 return -1;
     181             :         }
     182             : 
     183       25595 :         if (translate_pattern) {
     184             :                 /*
     185             :                   for older negotiated protocols it is possible to
     186             :                   translate the pattern to produce a "new style"
     187             :                   pattern that exactly matches w2k behaviour
     188             :                 */
     189       56950 :                 for (i=0;p[i];i++) {
     190       31355 :                         if (p[i] == UCS2_CHAR('?')) {
     191           0 :                                 p[i] = UCS2_CHAR('>');
     192       31355 :                         } else if (p[i] == UCS2_CHAR('.') &&
     193        1440 :                                    (p[i+1] == UCS2_CHAR('?') ||
     194        1440 :                                     p[i+1] == UCS2_CHAR('*') ||
     195        1440 :                                     p[i+1] == 0)) {
     196           0 :                                 p[i] = UCS2_CHAR('"');
     197       31355 :                         } else if (p[i] == UCS2_CHAR('*') && p[i+1] == UCS2_CHAR('.')) {
     198        1440 :                                 p[i] = UCS2_CHAR('<');
     199             :                         }
     200             :                 }
     201             :         }
     202             : 
     203       56950 :         for (count=i=0;p[i];i++) {
     204       31355 :                 if (p[i] == UCS2_CHAR('*') || p[i] == UCS2_CHAR('<')) count++;
     205             :         }
     206             : 
     207       25595 :         if (count != 0) {
     208       25595 :                 if (count == 1) {
     209             :                         /*
     210             :                          * We're doing this a LOT, so save the effort to allocate
     211             :                          */
     212       25595 :                         ZERO_STRUCT(one_max_n);
     213       25595 :                         max_n = &one_max_n;
     214             :                 }
     215             :                 else {
     216           0 :                         max_n = SMB_CALLOC_ARRAY(struct max_n, count);
     217           0 :                         if (!max_n) {
     218           0 :                                 TALLOC_FREE(p);
     219           0 :                                 TALLOC_FREE(s);
     220           0 :                                 return -1;
     221             :                         }
     222           0 :                         max_n_free = max_n;
     223             :                 }
     224             :         }
     225             : 
     226       25595 :         ret = ms_fnmatch_core(p, s, max_n, strrchr_w(s, UCS2_CHAR('.')), is_case_sensitive);
     227             : 
     228       25595 :         SAFE_FREE(max_n_free);
     229       25595 :         TALLOC_FREE(p);
     230       25595 :         TALLOC_FREE(s);
     231       25595 :         return ret;
     232             : }

Generated by: LCOV version 1.14