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
28 * @brief MS-style Filename matching
32 #include "lib/util/samba_util.h"
33 #include "libcli/smb/smb_constants.h"
35 static int null_match(const char *p
)
47 the max_n structure is purely for efficiency, it doesn't contribute
48 to the matching algorithm except by ensuring that the algorithm does
49 not grow exponentially
58 p and n are the pattern and string being matched. The max_n array is
59 an optimisation only. The ldot pointer is NULL if the string does
60 not contain a '.', otherwise it points at the last dot in 'n'.
62 static int ms_fnmatch_core(const char *p
, const char *n
,
63 struct max_n
*max_n
, const char *ldot
,
64 bool is_case_sensitive
)
70 while ((c
= next_codepoint(p
, &size
))) {
75 /* a '*' matches zero or more characters of any type */
76 if (max_n
!= NULL
&& max_n
->predot
&&
80 for (i
=0; n
[i
]; i
+= size_n
) {
81 next_codepoint(n
+i
, &size_n
);
82 if (ms_fnmatch_core(p
, n
+i
, max_n
+1, ldot
, is_case_sensitive
) == 0) {
86 if (max_n
!= NULL
&& (!max_n
->predot
||
93 /* a '<' matches zero or more characters of
94 any type, but stops matching at the last
96 if (max_n
!= NULL
&& max_n
->predot
&&
100 if (max_n
!= NULL
&& max_n
->postdot
&&
101 max_n
->postdot
<= n
&& n
<= ldot
) {
104 for (i
=0; n
[i
]; i
+= size_n
) {
105 next_codepoint(n
+i
, &size_n
);
106 if (ms_fnmatch_core(p
, n
+i
, max_n
+1, ldot
, is_case_sensitive
) == 0) return 0;
108 if (ms_fnmatch_core(p
, n
+i
+size_n
, max_n
+1, ldot
, is_case_sensitive
) == 0) return 0;
110 if (!max_n
->postdot
||
111 max_n
->postdot
> n
) {
118 if (max_n
!= NULL
&& (!max_n
->predot
||
119 max_n
->predot
> n
)) {
122 return null_match(p
);
125 /* a '?' matches any single character */
129 next_codepoint(n
, &size_n
);
134 /* a '?' matches any single character, but
135 treats '.' specially */
137 if (! n
[1] && null_match(p
) == 0) {
142 if (! *n
) return null_match(p
);
143 next_codepoint(n
, &size_n
);
148 /* a bit like a soft '.' */
149 if (*n
== 0 && null_match(p
) == 0) {
152 if (*n
!= '.') return -1;
153 next_codepoint(n
, &size_n
);
158 c2
= next_codepoint(n
, &size_n
);
160 if (is_case_sensitive
) {
163 if (codepoint_cmpi(c
, c2
) != 0) {
179 int ms_fnmatch_protocol(const char *pattern
, const char *string
, int protocol
,
180 bool is_case_sensitive
)
185 if (strcmp(string
, "..") == 0) {
189 if (strpbrk(pattern
, "<>*?\"") == NULL
) {
190 /* this is not just an optimisation - it is essential
191 for LANMAN1 correctness */
192 return strcasecmp_m(pattern
, string
);
195 if (protocol
<= PROTOCOL_LANMAN2
) {
196 char *p
= talloc_strdup(NULL
, pattern
);
201 for older negotiated protocols it is possible to
202 translate the pattern to produce a "new style"
203 pattern that exactly matches w2k behaviour
208 } else if (p
[i
] == '.' &&
213 } else if (p
[i
] == '*' &&
218 ret
= ms_fnmatch_protocol(p
, string
, PROTOCOL_NT1
,
224 for (count
=i
=0;pattern
[i
];i
++) {
225 if (pattern
[i
] == '*' || pattern
[i
] == '<') count
++;
228 /* If the pattern includes '*' or '<' */
230 struct max_n max_n
[count
];
232 memset(max_n
, 0, sizeof(struct max_n
) * count
);
234 ret
= ms_fnmatch_core(pattern
, string
, max_n
, strrchr(string
, '.'),
237 ret
= ms_fnmatch_core(pattern
, string
, NULL
, strrchr(string
, '.'),
245 /** a generic fnmatch function - uses for non-CIFS pattern matching */
246 int gen_fnmatch(const char *pattern
, const char *string
)
248 return ms_fnmatch_protocol(pattern
, string
, PROTOCOL_NT1
, false);