lib/ms_fnmatch.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    filename matching routine
00004    Copyright (C) Andrew Tridgell 1992-2004
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015    
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
00019 */
00020 
00021 /*
00022    This module was originally based on fnmatch.c copyright by the Free
00023    Software Foundation. It bears little (if any) resemblence to that
00024    code now
00025 */  
00026 
00027 
00028 #include "includes.h"
00029 
00030 static int null_match(const smb_ucs2_t *p)
00031 {
00032         for (;*p;p++) {
00033                 if (*p != UCS2_CHAR('*') &&
00034                     *p != UCS2_CHAR('<') &&
00035                     *p != UCS2_CHAR('"') &&
00036                     *p != UCS2_CHAR('>')) return -1;
00037         }
00038         return 0;
00039 }
00040 
00041 /*
00042   the max_n structure is purely for efficiency, it doesn't contribute
00043   to the matching algorithm except by ensuring that the algorithm does
00044   not grow exponentially
00045 */
00046 struct max_n {
00047         const smb_ucs2_t *predot;
00048         const smb_ucs2_t *postdot;
00049 };
00050 
00051 
00052 /*
00053   p and n are the pattern and string being matched. The max_n array is
00054   an optimisation only. The ldot pointer is NULL if the string does
00055   not contain a '.', otherwise it points at the last dot in 'n'.
00056 */
00057 static int ms_fnmatch_core(const smb_ucs2_t *p, const smb_ucs2_t *n, 
00058                            struct max_n *max_n, const smb_ucs2_t *ldot,
00059                            BOOL is_case_sensitive)
00060 {
00061         smb_ucs2_t c;
00062         int i;
00063 
00064         while ((c = *p++)) {
00065                 switch (c) {
00066                         /* a '*' matches zero or more characters of any type */
00067                 case UCS2_CHAR('*'):
00068                         if (max_n->predot && max_n->predot <= n) {
00069                                 return null_match(p);
00070                         }
00071                         for (i=0; n[i]; i++) {
00072                                 if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) {
00073                                         return 0;
00074                                 }
00075                         }
00076                         if (!max_n->predot || max_n->predot > n) max_n->predot = n;
00077                         return null_match(p);
00078 
00079                         /* a '<' matches zero or more characters of
00080                            any type, but stops matching at the last
00081                            '.' in the string. */
00082                 case UCS2_CHAR('<'):
00083                         if (max_n->predot && max_n->predot <= n) {
00084                                 return null_match(p);
00085                         }
00086                         if (max_n->postdot && max_n->postdot <= n && n <= ldot) {
00087                                 return -1;
00088                         }
00089                         for (i=0; n[i]; i++) {
00090                                 if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) return 0;
00091                                 if (n+i == ldot) {
00092                                         if (ms_fnmatch_core(p, n+i+1, max_n+1, ldot, is_case_sensitive) == 0) return 0;
00093                                         if (!max_n->postdot || max_n->postdot > n) max_n->postdot = n;
00094                                         return -1;
00095                                 }
00096                         }
00097                         if (!max_n->predot || max_n->predot > n) max_n->predot = n;
00098                         return null_match(p);
00099 
00100                         /* a '?' matches any single character */
00101                 case UCS2_CHAR('?'):
00102                         if (! *n) {
00103                                 return -1;
00104                         }
00105                         n++;
00106                         break;
00107 
00108                         /* a '?' matches any single character */
00109                 case UCS2_CHAR('>'):
00110                         if (n[0] == UCS2_CHAR('.')) {
00111                                 if (! n[1] && null_match(p) == 0) {
00112                                         return 0;
00113                                 }
00114                                 break;
00115                         }
00116                         if (! *n) return null_match(p);
00117                         n++;
00118                         break;
00119 
00120                 case UCS2_CHAR('"'):
00121                         if (*n == 0 && null_match(p) == 0) {
00122                                 return 0;
00123                         }
00124                         if (*n != UCS2_CHAR('.')) return -1;
00125                         n++;
00126                         break;
00127 
00128                 default:
00129                         if (c != *n) {
00130                                 if (is_case_sensitive) {
00131                                         return -1;
00132                                 }
00133                                 if (toupper_w(c) != toupper_w(*n)) {
00134                                         return -1;
00135                                 }
00136                         }
00137                         n++;
00138                         break;
00139                 }
00140         }
00141         
00142         if (! *n) {
00143                 return 0;
00144         }
00145         
00146         return -1;
00147 }
00148 
00149 int ms_fnmatch(const char *pattern, const char *string, BOOL translate_pattern,
00150                BOOL is_case_sensitive)
00151 {
00152         wpstring p, s;
00153         int ret, count, i;
00154         struct max_n *max_n = NULL;
00155 
00156         if (strcmp(string, "..") == 0) {
00157                 string = ".";
00158         }
00159 
00160         if (strpbrk(pattern, "<>*?\"") == NULL) {
00161                 /* this is not just an optmisation - it is essential
00162                    for LANMAN1 correctness */
00163                 if (is_case_sensitive) {
00164                         return strcmp(pattern, string);
00165                 } else {
00166                         return StrCaseCmp(pattern, string);
00167                 }
00168         }
00169 
00170         if (push_ucs2(NULL, p, pattern, sizeof(p), STR_TERMINATE) == (size_t)-1) {
00171                 /* Not quite the right answer, but finding the right one
00172                   under this failure case is expensive, and it's pretty close */
00173                 return -1;
00174         }
00175 
00176         if (push_ucs2(NULL, s, string, sizeof(s), STR_TERMINATE) == (size_t)-1) {
00177                 /* Not quite the right answer, but finding the right one
00178                    under this failure case is expensive, and it's pretty close */
00179                 return -1;
00180         }
00181 
00182         if (translate_pattern) {
00183                 /*
00184                   for older negotiated protocols it is possible to
00185                   translate the pattern to produce a "new style"
00186                   pattern that exactly matches w2k behaviour
00187                 */
00188                 for (i=0;p[i];i++) {
00189                         if (p[i] == UCS2_CHAR('?')) {
00190                                 p[i] = UCS2_CHAR('>');
00191                         } else if (p[i] == UCS2_CHAR('.') && 
00192                                    (p[i+1] == UCS2_CHAR('?') || 
00193                                     p[i+1] == UCS2_CHAR('*') ||
00194                                     p[i+1] == 0)) {
00195                                 p[i] = UCS2_CHAR('"');
00196                         } else if (p[i] == UCS2_CHAR('*') && p[i+1] == UCS2_CHAR('.')) {
00197                                 p[i] = UCS2_CHAR('<');
00198                         }
00199                 }
00200         }
00201 
00202         for (count=i=0;p[i];i++) {
00203                 if (p[i] == UCS2_CHAR('*') || p[i] == UCS2_CHAR('<')) count++;
00204         }
00205 
00206         if (count != 0) {
00207                 max_n = SMB_CALLOC_ARRAY(struct max_n, count);
00208                 if (!max_n) {
00209                         return -1;
00210                 }
00211         }
00212 
00213         ret = ms_fnmatch_core(p, s, max_n, strrchr_w(s, UCS2_CHAR('.')), is_case_sensitive);
00214 
00215         if (max_n) {
00216                 free(max_n);
00217         }
00218 
00219         return ret;
00220 }
00221 
00222 
00223 /* a generic fnmatch function - uses for non-CIFS pattern matching */
00224 int gen_fnmatch(const char *pattern, const char *string)
00225 {
00226         return ms_fnmatch(pattern, string, PROTOCOL_NT1, False);
00227 }

Sambaに対してSat Aug 29 21:22:58 2009に生成されました。  doxygen 1.4.7