/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2014 Nexenta Systems, Inc. All rights reserved.
*/
#if !defined(_KERNEL) && !defined(_FAKE_KERNEL)
#include <stdlib.h>
#include <string.h>
#else
#endif
/*
* Maximum recursion depth for the wildcard match functions.
* These functions may recurse when processing a '*'.
*/
struct match_priv {
int depth;
};
static int smb_match_private(const char *, const char *, struct match_priv *);
/*
* Return B_TRUE if pattern contains wildcards
*/
{
}
/*
* NT-compatible file name match function. [MS-FSA 3.1.4.4]
* Returns TRUE if there is a match.
*/
{
int rc;
/*
* Optimize common patterns that match everything:
* ("*", "<\"*") That second one is the converted
* form of "*.*" after smb_convert_wildcards() does
* its work on it for an old LM client. Note that a
* plain "*.*" never gets this far.
*/
if (p[0] == '*' && p[1] == '\0')
return (B_TRUE);
if (p[0] == '<' && p[1] == '\"' && p[2] == '*' && p[3] == '\0')
return (B_TRUE);
/*
* Match string ".." as if "." This is Windows behavior
* (not mentioned in MS-FSA) that was determined using
* the Samba masktest program.
*/
if (s[0] == '.' && s[1] == '.' && s[2] == '\0')
s++;
/*
* Optimize simple patterns (no wildcards)
*/
if (ci)
rc = smb_strcasecmp(p, s, 0);
else
return (rc == 0);
}
/*
* Do real wildcard match.
*/
return (rc == 1);
}
/*
* Internal file name match function. [MS-FSA 3.1.4.4]
* This does the full expression evaluation.
*
* '*' matches zero of more of any characters.
* '?' matches exactly one of any character.
* '<' matches any string up through the last dot or EOS.
* '>' matches any one char not a dot, dot at EOS, or EOS.
* '"' matches a dot, or EOS.
*
* Returns:
* 1 match
* 0 no-match
* -1 no-match, error (illseq, too many wildcards in pattern, ...)
*
* Note that both the pattern and the string are in multi-byte form.
*
* The implementation of this is quite tricky. First note that it
* can call itself recursively, though it limits the recursion depth.
* Each switch case in the while loop can basically do one of three
* things: (a) return "Yes, match", (b) return "not a match", or
* continue processing the match pattern. The cases for wildcards
* that may match a variable number of characters ('*' and '<') do
* recursive calls, looking for a match of the remaining pattern,
* starting at the current and later positions in the string.
*/
static int
{
const char *limit;
int rc;
return (-1);
/*
* Advance over one multi-byte char, used in cases like
* '?' or '>' where "match one character" needs to be
* interpreted as "match one multi-byte sequence".
*
* This macro needs to consume the semicolon following
* each place it appears, so this is carefully written
*/
return (-1); \
else \
/*
* We move pat forward in each switch case so that the
* default case can move it by a whole multi-byte seq.
*/
switch (pc) {
case '?': /* exactly one of any character */
pat++;
if (*str != '\0') {
continue;
}
/* EOS: no-match */
return (0);
case '*': /* zero or more of any characters */
pat++;
/* Optimize '*' at end of pattern. */
if (*pat == '\0')
return (1); /* match */
while (*str != '\0') {
if (rc != 0)
return (rc); /* match */
}
continue;
case '<': /* any string up through the last dot or EOS */
pat++;
limit++;
if (rc != 0)
return (rc); /* match */
}
continue;
case '>': /* anything not a dot, dot at EOS, or EOS */
pat++;
if (*str == '.') {
/* dot at EOS */
str++; /* ADVANCE over '.' */
continue;
}
/* dot NOT at EOS: no-match */
return (0);
}
if (*str != '\0') {
/* something not a dot */
continue;
}
continue;
case '\"': /* dot, or EOS */
pat++;
if (*str == '.') {
str++; /* ADVANCE over '.' */
continue;
}
if (*str == '\0') {
continue;
}
/* something else: no-match */
return (0);
default: /* not a wildcard */
/* make sure we advance */
return (-1);
continue;
}
continue;
}
}
return (0); /* no-match */
}
}
return (*str == '\0');
}