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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 This module was originally based on fnmatch.c copyright by the Free
23 Software Foundation. It bears little (if any) resemblence to that
29 * @brief MS-style Filename matching
34 static int null_match(const char *p)
46 the max_n structure is purely for efficiency, it doesn't contribute
47 to the matching algorithm except by ensuring that the algorithm does
48 not grow exponentially
57 p and n are the pattern and string being matched. The max_n array is
58 an optimisation only. The ldot pointer is NULL if the string does
59 not contain a '.', otherwise it points at the last dot in 'n'.
61 static int ms_fnmatch_core(const char *p, const char *n,
62 struct max_n *max_n, const char *ldot)
68 while ((c = next_codepoint(p, &size))) {
73 /* a '*' matches zero or more characters of any type */
74 if (max_n->predot && max_n->predot <= n) {
77 for (i=0; n[i]; i += size_n) {
78 next_codepoint(n+i, &size_n);
79 if (ms_fnmatch_core(p, n+i, max_n+1, ldot) == 0) {
83 if (!max_n->predot || max_n->predot > n) max_n->predot = n;
87 /* a '<' matches zero or more characters of
88 any type, but stops matching at the last
90 if (max_n->predot && max_n->predot <= n) {
93 if (max_n->postdot && max_n->postdot <= n && n <= ldot) {
96 for (i=0; n[i]; i += size_n) {
97 next_codepoint(n+i, &size_n);
98 if (ms_fnmatch_core(p, n+i, max_n+1, ldot) == 0) return 0;
100 if (ms_fnmatch_core(p, n+i+size_n, max_n+1, ldot) == 0) return 0;
101 if (!max_n->postdot || max_n->postdot > n) max_n->postdot = n;
105 if (!max_n->predot || max_n->predot > n) max_n->predot = n;
106 return null_match(p);
109 /* a '?' matches any single character */
113 next_codepoint(n, &size_n);
118 /* a '?' matches any single character, but
119 treats '.' specially */
121 if (! n[1] && null_match(p) == 0) {
126 if (! *n) return null_match(p);
127 next_codepoint(n, &size_n);
132 /* a bit like a soft '.' */
133 if (*n == 0 && null_match(p) == 0) {
136 if (*n != '.') return -1;
137 next_codepoint(n, &size_n);
142 c2 = next_codepoint(n, &size_n);
143 if (c != c2 && codepoint_cmpi(c, c2) != 0) {
158 int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol)
161 struct max_n *max_n = NULL;
163 if (strcmp(string, "..") == 0) {
167 if (strpbrk(pattern, "<>*?\"") == NULL) {
168 /* this is not just an optimisation - it is essential
169 for LANMAN1 correctness */
170 return strcasecmp_m(pattern, string);
173 if (protocol <= PROTOCOL_LANMAN2) {
174 char *p = talloc_strdup(NULL, pattern);
179 for older negotiated protocols it is possible to
180 translate the pattern to produce a "new style"
181 pattern that exactly matches w2k behaviour
186 } else if (p[i] == '.' &&
191 } else if (p[i] == '*' &&
196 ret = ms_fnmatch(p, string, PROTOCOL_NT1);
201 for (count=i=0;pattern[i];i++) {
202 if (pattern[i] == '*' || pattern[i] == '<') count++;
205 max_n = talloc_array(NULL, struct max_n, count);
209 memset(max_n, 0, sizeof(struct max_n) * count);
211 ret = ms_fnmatch_core(pattern, string, max_n, strrchr(string, '.'));
219 /** a generic fnmatch function - uses for non-CIFS pattern matching */
220 int gen_fnmatch(const char *pattern, const char *string)
222 return ms_fnmatch(pattern, string, PROTOCOL_NT1);