View | Details | Raw Unified | Return to bug 63019
Collapse All | Expand All

(-)samba-3.0.7-orig/source/lib/ms_fnmatch.c (-166 / +134 lines)
Lines 1-7 Link Here
1
/* 
1
/* 
2
   Unix SMB/CIFS implementation.
2
   Unix SMB/CIFS implementation.
3
   filename matching routine
3
   filename matching routine
4
   Copyright (C) Andrew Tridgell 1992-1998 
4
   Copyright (C) Andrew Tridgell 1992-2004
5
5
6
   This program is free software; you can redistribute it and/or modify
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
7
   it under the terms of the GNU General Public License as published by
Lines 15-243 Link Here
15
   
15
   
16
   You should have received a copy of the GNU General Public License
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
17
   along with this program; if not, write to the Free Software
18
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
18
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  
19
*/
19
20
20
/*
21
/*
21
   This module was originally based on fnmatch.c copyright by the Free
22
   This module was originally based on fnmatch.c copyright by the Free
22
   Software Foundation. It bears little resemblence to that code now 
23
   Software Foundation. It bears little (if any) resemblence to that
24
   code now
23
*/  
25
*/  
24
26
25
27
26
#if FNMATCH_TEST
27
#include <stdio.h>
28
#include <stdlib.h>
29
#else
30
#include "includes.h"
28
#include "includes.h"
31
#endif
29
30
static int null_match(const smb_ucs2_t *p)
31
{
32
	for (;*p;p++) {
33
		if (*p != UCS2_CHAR('*') &&
34
		    *p != UCS2_CHAR('<') &&
35
		    *p != UCS2_CHAR('"') &&
36
		    *p != UCS2_CHAR('>')) return -1;
37
	}
38
	return 0;
39
}
40
41
/*
42
  the max_n structure is purely for efficiency, it doesn't contribute
43
  to the matching algorithm except by ensuring that the algorithm does
44
  not grow exponentially
45
*/
46
struct max_n {
47
	const smb_ucs2_t *predot;
48
	const smb_ucs2_t *postdot;
49
};
50
32
51
33
/* 
52
/* 
34
   bugger. we need a separate wildcard routine for older versions
53
  p and n are the pattern and string being matched. The max_n array is
35
   of the protocol. This is not yet perfect, but its a lot
54
  an optimisation only. The ldot pointer is NULL if the string does
36
   better than what we had */
55
  not contain a '.', otherwise it points at the last dot in 'n'.
37
static int ms_fnmatch_lanman_core(const smb_ucs2_t *pattern, 
56
*/
38
				  const smb_ucs2_t *string,
57
static int ms_fnmatch_core(const smb_ucs2_t *p, const smb_ucs2_t *n, 
39
				  BOOL case_sensitive)
58
			   struct max_n *max_n, const smb_ucs2_t *ldot,
59
			   BOOL is_case_sensitive)
40
{
60
{
41
	const smb_ucs2_t *p = pattern, *n = string;
42
	smb_ucs2_t c;
61
	smb_ucs2_t c;
43
62
	int i;
44
	if (strcmp_wa(p, "?")==0 && strcmp_wa(n, ".")) goto match;
45
63
46
	while ((c = *p++)) {
64
	while ((c = *p++)) {
47
		switch (c) {
65
		switch (c) {
48
		case UCS2_CHAR('.'):
66
			/* a '*' matches zero or more characters of any type */
49
			if (! *n) goto next;
50
			if (*n != UCS2_CHAR('.')) goto nomatch;
51
			n++;
52
			break;
53
54
		case UCS2_CHAR('?'):
55
			if (! *n) goto next;
56
			if ((*n == UCS2_CHAR('.') && 
57
			     n[1] != UCS2_CHAR('.')) || ! *n) 
58
				goto next;
59
			n++;
60
			break;
61
62
		case UCS2_CHAR('>'):
63
			if (! *n) goto next;
64
			if (n[0] == UCS2_CHAR('.')) {
65
				if (! n[1] && ms_fnmatch_lanman_core(p, n+1, case_sensitive) == 0) goto match;
66
				if (ms_fnmatch_lanman_core(p, n, case_sensitive) == 0) goto match;
67
				goto nomatch;
68
			}
69
			n++;
70
			break;
71
72
		case UCS2_CHAR('*'):
67
		case UCS2_CHAR('*'):
73
			if (! *n) goto next;
68
			if (max_n->predot && max_n->predot <= n) {
74
			if (! *p) goto match;
69
				return null_match(p);
75
			for (; *n; n++) {
76
				if (ms_fnmatch_lanman_core(p, n, case_sensitive) == 0) goto match;
77
			}
70
			}
78
			break;
71
			for (i=0; n[i]; i++) {
79
72
				if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) {
80
		case UCS2_CHAR('<'):
73
					return 0;
81
			for (; *n; n++) {
82
				if (ms_fnmatch_lanman_core(p, n, case_sensitive) == 0) goto match;
83
				if (*n == UCS2_CHAR('.') && 
84
				    !strchr_w(n+1,UCS2_CHAR('.'))) {
85
					n++;
86
					break;
87
				}
74
				}
88
			}
75
			}
89
			break;
76
			if (!max_n->predot || max_n->predot > n) max_n->predot = n;
90
77
			return null_match(p);
91
		case UCS2_CHAR('"'):
92
			if (*n == 0 && ms_fnmatch_lanman_core(p, n, case_sensitive) == 0) goto match;
93
			if (*n != UCS2_CHAR('.')) goto nomatch;
94
			n++;
95
			break;
96
78
97
		default:
79
			/* a '<' matches zero or more characters of
98
			if (case_sensitive) {
80
			   any type, but stops matching at the last
99
				if (c != *n) goto nomatch;
81
			   '.' in the string. */
100
			} else {
82
		case UCS2_CHAR('<'):
101
				if (tolower_w(c) != tolower_w(*n)) goto nomatch;
83
			if (max_n->predot && max_n->predot <= n) {
102
			}
84
				return null_match(p);
103
			n++;
104
		}
105
	}
85
	}
106
	
86
			if (max_n->postdot && max_n->postdot <= n && n <= ldot) {
107
	if (! *n) goto match;
108
	
109
 nomatch:
110
	/*
111
	if (verbose) printf("NOMATCH pattern=[%s] string=[%s]\n", pattern, string);
112
	*/
113
	return -1;
87
	return -1;
114
115
next:
116
	if (ms_fnmatch_lanman_core(p, n, case_sensitive) == 0) goto match;
117
        goto nomatch;
118
119
 match:
120
	/*
121
	if (verbose) printf("MATCH   pattern=[%s] string=[%s]\n", pattern, string);
122
	*/
123
	return 0;
124
}
125
126
static int ms_fnmatch_lanman1(const smb_ucs2_t *pattern, 
127
			      const smb_ucs2_t *string, BOOL case_sensitive)
128
{
129
	if (!strpbrk_wa(pattern, "?*<>\"")) {
130
		smb_ucs2_t s[] = {UCS2_CHAR('.'), 0};
131
		if (strcmp_wa(string,"..") == 0) string = s;
132
		return strcasecmp_w(pattern, string);
133
	}
88
	}
134
89
			for (i=0; n[i]; i++) {
135
	if (strcmp_wa(string,"..") == 0 || strcmp_wa(string,".") == 0) {
90
				if (ms_fnmatch_core(p, n+i, max_n+1, ldot, is_case_sensitive) == 0) return 0;
136
		smb_ucs2_t dot[] = {UCS2_CHAR('.'), 0};
91
				if (n+i == ldot) {
137
		smb_ucs2_t dotdot[] = {UCS2_CHAR('.'), UCS2_CHAR('.'), 0};
92
					if (ms_fnmatch_core(p, n+i+1, max_n+1, ldot, is_case_sensitive) == 0) return 0;
138
		return ms_fnmatch_lanman_core(pattern, dotdot, case_sensitive) &&
93
					if (!max_n->postdot || max_n->postdot > n) max_n->postdot = n;
139
			ms_fnmatch_lanman_core(pattern, dot, case_sensitive);
94
					return -1;
140
	}
95
	}
141
142
	return ms_fnmatch_lanman_core(pattern, string, case_sensitive);
143
}
144
145
146
/* the following function was derived using the masktest utility -
147
   after years of effort we finally have a perfect MS wildcard
148
   matching routine! 
149
150
   NOTE: this matches only filenames with no directory component
151
152
   Returns 0 on match, -1 on fail.
153
*/
154
static int ms_fnmatch_w(const smb_ucs2_t *pattern, const smb_ucs2_t *string, 
155
			int protocol, BOOL case_sensitive)
156
{
157
	const smb_ucs2_t *p = pattern, *n = string;
158
	smb_ucs2_t c;
159
160
	if (protocol <= PROTOCOL_LANMAN2) {
161
		return ms_fnmatch_lanman1(pattern, string, case_sensitive);
162
	}
96
	}
97
			if (!max_n->predot || max_n->predot > n) max_n->predot = n;
98
			return null_match(p);
163
99
164
	while ((c = *p++)) {
100
			/* a '?' matches any single character */
165
		switch (c) {
166
		case UCS2_CHAR('?'):
101
		case UCS2_CHAR('?'):
167
			if (! *n) return -1;
102
			if (! *n) {
103
				return -1;
104
			}
168
			n++;
105
			n++;
169
			break;
106
			break;
170
107
108
			/* a '?' matches any single character */
171
		case UCS2_CHAR('>'):
109
		case UCS2_CHAR('>'):
172
			if (n[0] == UCS2_CHAR('.')) {
110
			if (n[0] == UCS2_CHAR('.')) {
173
				if (! n[1] && ms_fnmatch_w(p, n+1, protocol, case_sensitive) == 0) return 0;
111
				if (! n[1] && null_match(p) == 0) {
174
				if (ms_fnmatch_w(p, n, protocol, case_sensitive) == 0) return 0;
112
					return 0;
175
				return -1;
176
			}
113
			}
177
			if (! *n) return ms_fnmatch_w(p, n, protocol, case_sensitive);
178
			n++;
179
			break;
114
			break;
180
181
		case UCS2_CHAR('*'):
182
			for (; *n; n++) {
183
				if (ms_fnmatch_w(p, n, protocol, case_sensitive) == 0) return 0;
184
			}
115
			}
185
			break;
116
			if (! *n) return null_match(p);
186
187
		case UCS2_CHAR('<'):
188
			for (; *n; n++) {
189
				if (ms_fnmatch_w(p, n, protocol, case_sensitive) == 0) return 0;
190
				if (*n == UCS2_CHAR('.') && !strchr_wa(n+1,'.')) {
191
					n++;
117
					n++;
192
					break;
118
					break;
193
				}
194
			}
195
			break;
196
119
197
		case UCS2_CHAR('"'):
120
		case UCS2_CHAR('"'):
198
			if (*n == 0 && ms_fnmatch_w(p, n, protocol, case_sensitive) == 0) return 0;
121
			if (*n == 0 && null_match(p) == 0) {
122
				return 0;
123
			}
199
			if (*n != UCS2_CHAR('.')) return -1;
124
			if (*n != UCS2_CHAR('.')) return -1;
200
			n++;
125
			n++;
201
			break;
126
			break;
202
127
203
		default:
128
		default:
204
			if (case_sensitive) {
129
			if (c != *n) {
205
				if (c != *n) return -1;
130
				if (is_case_sensitive) {
206
			} else {
131
					return -1;
207
				if (tolower_w(c) != tolower_w(*n)) return -1;
132
				}
133
				if (toupper_w(c) != toupper_w(*n)) {
134
					return -1;
135
				}
208
			}
136
			}
209
			n++;
137
			n++;
138
			break;
210
		}
139
		}
211
	}
140
	}
212
	
141
	
213
	if (! *n) return 0;
142
	if (! *n) {
143
		return 0;
144
	}
214
	
145
	
215
	return -1;
146
	return -1;
216
}
147
}
217
148
218
int ms_fnmatch(const char *pattern, const char *string, int protocol, 
149
int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol, 
219
	       BOOL case_senstive)
150
	       BOOL is_case_sensitive)
220
{
151
{
221
	wpstring buffer_pattern, buffer_string;
152
	wpstring p, s;
222
	int ret;
153
	int ret, count, i;
223
	size_t size;
154
	struct max_n *max_n = NULL;
155
156
	if (strcmp(string, "..") == 0) {
157
		string = ".";
158
	}
224
159
225
	size = push_ucs2(NULL, buffer_pattern, pattern, sizeof(buffer_pattern), STR_TERMINATE);
160
	if (strpbrk(pattern, "<>*?\"") == NULL) {
226
	if (size == (size_t)-1) {
161
		/* this is not just an optmisation - it is essential
227
		return -1;
162
		   for LANMAN1 correctness */
228
		/* Not quite the right answer, but finding the right one
163
		if (is_case_sensitive) {
229
		   under this failure case is expensive, and it's pretty close */
164
			return strcmp(pattern, string);
165
		} else {
166
			return StrCaseCmp(pattern, string);
167
		}
230
	}
168
	}
231
	
169
	
232
	size = push_ucs2(NULL, buffer_string, string, sizeof(buffer_string), STR_TERMINATE);
170
	pstrcpy_wa(p, pattern);
233
	if (size == (size_t)-1) {
171
	pstrcpy_wa(s, string);
172
173
	if (protocol <= PROTOCOL_LANMAN2) {
174
		/*
175
		  for older negotiated protocols it is possible to
176
		  translate the pattern to produce a "new style"
177
		  pattern that exactly matches w2k behaviour
178
		*/
179
		for (i=0;p[i];i++) {
180
			if (p[i] == UCS2_CHAR('?')) {
181
				p[i] = UCS2_CHAR('>');
182
			} else if (p[i] == UCS2_CHAR('.') && 
183
				   (p[i+1] == UCS2_CHAR('?') || 
184
				    p[i+1] == UCS2_CHAR('*') ||
185
				    p[i+1] == 0)) {
186
				p[i] = UCS2_CHAR('"');
187
			} else if (p[i] == UCS2_CHAR('*') && p[i+1] == UCS2_CHAR('.')) {
188
				p[i] = UCS2_CHAR('<');
189
			}
190
		}
191
	}
192
193
	for (count=i=0;p[i];i++) {
194
		if (p[i] == UCS2_CHAR('*') || p[i] == UCS2_CHAR('<')) count++;
195
	}
196
197
	if (count != 0) {
198
		max_n = calloc(sizeof(struct max_n), count);
199
		if (!max_n) {
234
		return -1;
200
		return -1;
235
		/* Not quite the right answer, but finding the right one
201
		}
236
		   under this failure case is expensive, and it's pretty close */
237
	}
202
	}
238
203
239
	ret = ms_fnmatch_w(buffer_pattern, buffer_string, protocol, case_senstive);
204
	ret = ms_fnmatch_core(p, s, max_n, strrchr_w(s, UCS2_CHAR('.')), is_case_sensitive);
240
 	DEBUG(10,("ms_fnmatch(%s,%s) -> %d\n", pattern, string, ret));
205
206
	if (max_n) {
207
		free(max_n);
208
	}
241
209
242
	return ret;
210
	return ret;
243
}
211
}
Lines 245-249 Link Here
245
/* a generic fnmatch function - uses for non-CIFS pattern matching */
214
/* a generic fnmatch function - uses for non-CIFS pattern matching */
246
int gen_fnmatch(const char *pattern, const char *string)
215
int gen_fnmatch(const char *pattern, const char *string)
247
{
216
{
248
	return ms_fnmatch(pattern, string, PROTOCOL_NT1, True);
217
	return ms_fnmatch(pattern, string, PROTOCOL_NT1, False);
249
}
218
}

Return to bug 63019