This commit was generated by cvs2svn to compensate for changes in r30,
[samba.git] / source4 / lib / ms_fnmatch.c
1 /* 
2    Unix SMB/CIFS implementation.
3    filename matching routine
4    Copyright (C) Andrew Tridgell 1992-1998 
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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 /*
21    This module was originally based on fnmatch.c copyright by the Free
22    Software Foundation. It bears little resemblence to that code now 
23 */  
24
25
26 #if FNMATCH_TEST
27 #include <stdio.h>
28 #include <stdlib.h>
29 #else
30 #include "includes.h"
31 #endif
32
33 /* 
34    bugger. we need a separate wildcard routine for older versions
35    of the protocol. This is not yet perfect, but its a lot
36    better than what we had */
37 static int ms_fnmatch_lanman_core(const smb_ucs2_t *pattern, 
38                                   const smb_ucs2_t *string)
39 {
40         const smb_ucs2_t *p = pattern, *n = string;
41         smb_ucs2_t c;
42
43         if (strcmp_wa(p, "?")==0 && strcmp_wa(n, ".")) goto match;
44
45         while ((c = *p++)) {
46                 switch (c) {
47                 case UCS2_CHAR('.'):
48                         if (! *n) goto next;
49                         if (*n != UCS2_CHAR('.')) goto nomatch;
50                         n++;
51                         break;
52
53                 case UCS2_CHAR('?'):
54                         if (! *n) goto next;
55                         if ((*n == UCS2_CHAR('.') && 
56                              n[1] != UCS2_CHAR('.')) || ! *n) 
57                                 goto next;
58                         n++;
59                         break;
60
61                 case UCS2_CHAR('>'):
62                         if (! *n) goto next;
63                         if (n[0] == UCS2_CHAR('.')) {
64                                 if (! n[1] && ms_fnmatch_lanman_core(p, n+1) == 0) goto match;
65                                 if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
66                                 goto nomatch;
67                         }
68                         n++;
69                         break;
70
71                 case UCS2_CHAR('*'):
72                         if (! *n) goto next;
73                         if (! *p) goto match;
74                         for (; *n; n++) {
75                                 if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
76                         }
77                         break;
78
79                 case UCS2_CHAR('<'):
80                         for (; *n; n++) {
81                                 if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
82                                 if (*n == UCS2_CHAR('.') && 
83                                     !strchr_w(n+1,UCS2_CHAR('.'))) {
84                                         n++;
85                                         break;
86                                 }
87                         }
88                         break;
89
90                 case UCS2_CHAR('"'):
91                         if (*n == 0 && ms_fnmatch_lanman_core(p, n) == 0) goto match;
92                         if (*n != UCS2_CHAR('.')) goto nomatch;
93                         n++;
94                         break;
95
96                 default:
97                         if (c != *n) goto nomatch;
98                         n++;
99                 }
100         }
101         
102         if (! *n) goto match;
103         
104  nomatch:
105         /*
106         if (verbose) printf("NOMATCH pattern=[%s] string=[%s]\n", pattern, string);
107         */
108         return -1;
109
110 next:
111         if (ms_fnmatch_lanman_core(p, n) == 0) goto match;
112         goto nomatch;
113
114  match:
115         /*
116         if (verbose) printf("MATCH   pattern=[%s] string=[%s]\n", pattern, string);
117         */
118         return 0;
119 }
120
121 static int ms_fnmatch_lanman1(const smb_ucs2_t *pattern, const smb_ucs2_t *string)
122 {
123         if (!strpbrk_wa(pattern, "?*<>\"")) {
124                 smb_ucs2_t s[] = {UCS2_CHAR('.'), 0};
125                 if (strcmp_wa(string,"..") == 0) string = s;
126                 return strcasecmp_w(pattern, string);
127         }
128
129         if (strcmp_wa(string,"..") == 0 || strcmp_wa(string,".") == 0) {
130                 smb_ucs2_t dot[] = {UCS2_CHAR('.'), 0};
131                 smb_ucs2_t dotdot[] = {UCS2_CHAR('.'), UCS2_CHAR('.'), 0};
132                 return ms_fnmatch_lanman_core(pattern, dotdot) &&
133                         ms_fnmatch_lanman_core(pattern, dot);
134         }
135
136         return ms_fnmatch_lanman_core(pattern, string);
137 }
138
139
140 /* the following function was derived using the masktest utility -
141    after years of effort we finally have a perfect MS wildcard
142    matching routine! 
143
144    NOTE: this matches only filenames with no directory component
145
146    Returns 0 on match, -1 on fail.
147 */
148 static int ms_fnmatch_w(const smb_ucs2_t *pattern, const smb_ucs2_t *string, 
149                         enum protocol_types protocol)
150 {
151         const smb_ucs2_t *p = pattern, *n = string;
152         smb_ucs2_t c;
153
154         if (protocol <= PROTOCOL_LANMAN2) {
155                 return ms_fnmatch_lanman1(pattern, string);
156         }
157
158         while ((c = *p++)) {
159                 switch (c) {
160                 case UCS2_CHAR('?'):
161                         if (! *n) return -1;
162                         n++;
163                         break;
164
165                 case UCS2_CHAR('>'):
166                         if (n[0] == UCS2_CHAR('.')) {
167                                 if (! n[1] && ms_fnmatch_w(p, n+1, protocol) == 0) return 0;
168                                 if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
169                                 return -1;
170                         }
171                         if (! *n) return ms_fnmatch_w(p, n, protocol);
172                         n++;
173                         break;
174
175                 case UCS2_CHAR('*'):
176                         for (; *n; n++) {
177                                 if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
178                         }
179                         break;
180
181                 case UCS2_CHAR('<'):
182                         for (; *n; n++) {
183                                 if (ms_fnmatch_w(p, n, protocol) == 0) return 0;
184                                 if (*n == UCS2_CHAR('.') && !strchr_wa(n+1,'.')) {
185                                         n++;
186                                         break;
187                                 }
188                         }
189                         break;
190
191                 case UCS2_CHAR('"'):
192                         if (*n == 0 && ms_fnmatch_w(p, n, protocol) == 0) return 0;
193                         if (*n != UCS2_CHAR('.')) return -1;
194                         n++;
195                         break;
196
197                 default:
198                         if (c != *n) return -1;
199                         n++;
200                 }
201         }
202         
203         if (! *n) return 0;
204         
205         return -1;
206 }
207
208
209 int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol)
210 {
211         wpstring p, s;
212         int ret;
213
214         pstrcpy_wa(p, pattern);
215         pstrcpy_wa(s, string);
216
217         ret = ms_fnmatch_w(p, s, protocol);
218 /*      DEBUG(0,("ms_fnmatch(%s,%s) -> %d\n", pattern, string, ret)); */
219         return ret;
220 }
221
222 /* a generic fnmatch function - uses for non-CIFS pattern matching */
223 int gen_fnmatch(const char *pattern, const char *string)
224 {
225         return ms_fnmatch(pattern, string, PROTOCOL_NT1);
226 }