2 Unix SMB/CIFS implementation.
3 filename matching routine
4 Copyright (C) Andrew Tridgell 1992-2004
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.
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.
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/>.
21 This module was originally based on fnmatch.c copyright by the Free
22 Software Foundation. It bears little (if any) resemblance to that
29 static int null_match(const smb_ucs2_t
*p
)
32 if (*p
!= UCS2_CHAR('*') &&
33 *p
!= UCS2_CHAR('<') &&
34 *p
!= UCS2_CHAR('"') &&
35 *p
!= UCS2_CHAR('>')) return -1;
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
46 const smb_ucs2_t
*predot
;
47 const smb_ucs2_t
*postdot
;
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'.
56 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
)
65 /* a '*' matches zero or more characters of any type */
67 if (max_n
->predot
&& max_n
->predot
<= n
) {
70 for (i
=0; n
[i
]; i
++) {
71 if (ms_fnmatch_core(p
, n
+i
, max_n
+1, ldot
, is_case_sensitive
) == 0) {
75 if (!max_n
->predot
|| max_n
->predot
> n
) max_n
->predot
= n
;
78 /* a '<' matches zero or more characters of
79 any type, but stops matching at the last
82 if (max_n
->predot
&& max_n
->predot
<= n
) {
85 if (max_n
->postdot
&& max_n
->postdot
<= n
&& n
<= ldot
) {
88 for (i
=0; n
[i
]; i
++) {
89 if (ms_fnmatch_core(p
, n
+i
, max_n
+1, ldot
, is_case_sensitive
) == 0) return 0;
91 if (ms_fnmatch_core(p
, n
+i
+1, max_n
+1, ldot
, is_case_sensitive
) == 0) return 0;
92 if (!max_n
->postdot
|| max_n
->postdot
> n
) max_n
->postdot
= n
;
96 if (!max_n
->predot
|| max_n
->predot
> n
) max_n
->predot
= n
;
99 /* a '?' matches any single character */
107 /* a '?' matches any single character */
109 if (n
[0] == UCS2_CHAR('.')) {
110 if (! n
[1] && null_match(p
) == 0) {
115 if (! *n
) return null_match(p
);
120 if (*n
== 0 && null_match(p
) == 0) {
123 if (*n
!= UCS2_CHAR('.')) return -1;
129 if (is_case_sensitive
) {
132 if (toupper_w(c
) != toupper_w(*n
)) {
148 int ms_fnmatch(const char *pattern
, const char *string
, bool translate_pattern
,
149 bool is_case_sensitive
)
151 smb_ucs2_t
*p
= NULL
;
152 smb_ucs2_t
*s
= NULL
;
155 struct max_n
*max_n
= NULL
;
156 struct max_n
*max_n_free
= NULL
;
157 struct max_n one_max_n
;
158 size_t converted_size
;
160 if (ISDOTDOT(string
)) {
164 if (strpbrk(pattern
, "<>*?\"") == NULL
) {
165 /* this is not just an optimisation - it is essential
166 for LANMAN1 correctness */
167 if (is_case_sensitive
) {
168 return strcmp(pattern
, string
);
170 return strcasecmp_m(pattern
, string
);
174 if (!push_ucs2_talloc(talloc_tos(), &p
, pattern
, &converted_size
)) {
178 if (!push_ucs2_talloc(talloc_tos(), &s
, string
, &converted_size
)) {
183 if (translate_pattern
) {
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
190 if (p
[i
] == UCS2_CHAR('?')) {
191 p
[i
] = UCS2_CHAR('>');
192 } else if (p
[i
] == UCS2_CHAR('.') &&
193 (p
[i
+1] == UCS2_CHAR('?') ||
194 p
[i
+1] == UCS2_CHAR('*') ||
196 p
[i
] = UCS2_CHAR('"');
197 } else if (p
[i
] == UCS2_CHAR('*') && p
[i
+1] == UCS2_CHAR('.')) {
198 p
[i
] = UCS2_CHAR('<');
203 for (count
=i
=0;p
[i
];i
++) {
204 if (p
[i
] == UCS2_CHAR('*') || p
[i
] == UCS2_CHAR('<')) count
++;
210 * We're doing this a LOT, so save the effort to allocate
212 ZERO_STRUCT(one_max_n
);
216 max_n
= SMB_CALLOC_ARRAY(struct max_n
, count
);
226 ret
= ms_fnmatch_core(p
, s
, max_n
, strrchr_w(s
, UCS2_CHAR('.')), is_case_sensitive
);
228 SAFE_FREE(max_n_free
);