mirror of
https://github.com/samba-team/samba.git
synced 2025-12-19 12:23:49 +03:00
Newly re-written do_match and mask_match functions, with the
help of Ums Harald <Harald.Ums@pro-sieben.de>, who has been testing our 8.3 wildcards with a test suite. With his new code for 8.3 matching, this is the test done (I'm quoting from his email) "I tested it by generating a directory with about 7600 Files and run automatc tests with about 4000 patterns. The result from Win95 -> WinNT and Win95 -> Samba where identical according to diff." I have also re-written the long filename wildcard code, so that doing DIR a*z now matches files : AAA.BBB.CCCC....ZZZZ correctly, and other fixes besides. I sincerely hope I can lay this (horrid) issue to rest now :-). Jeremy.
This commit is contained in:
@@ -2013,6 +2013,7 @@ BOOL string_init(char **dest,char *src);
|
|||||||
void string_free(char **s);
|
void string_free(char **s);
|
||||||
BOOL string_set(char **dest,char *src);
|
BOOL string_set(char **dest,char *src);
|
||||||
BOOL string_sub(char *s,char *pattern,char *insert);
|
BOOL string_sub(char *s,char *pattern,char *insert);
|
||||||
|
BOOL mask_match(char *str, char *regexp, int case_sig, BOOL trans2);
|
||||||
BOOL do_match(char *str, char *regexp, int case_sig);
|
BOOL do_match(char *str, char *regexp, int case_sig);
|
||||||
BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2);
|
BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2);
|
||||||
void become_daemon(void);
|
void become_daemon(void);
|
||||||
|
|||||||
@@ -1858,9 +1858,14 @@ BOOL strhasupper(char *s)
|
|||||||
else
|
else
|
||||||
#endif /* KANJI_WIN95_COMPATIBILITY */
|
#endif /* KANJI_WIN95_COMPATIBILITY */
|
||||||
{
|
{
|
||||||
if (isupper(*s))
|
int skip = skip_multibyte_char( *s );
|
||||||
return(True);
|
if( skip != 0 )
|
||||||
s++;
|
s += skip;
|
||||||
|
else {
|
||||||
|
if (isupper(*s))
|
||||||
|
return(True);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(False);
|
return(False);
|
||||||
@@ -1908,9 +1913,14 @@ BOOL strhaslower(char *s)
|
|||||||
else
|
else
|
||||||
#endif /* KANJI_WIN95_COMPATIBILITY */
|
#endif /* KANJI_WIN95_COMPATIBILITY */
|
||||||
{
|
{
|
||||||
if (islower(*s))
|
int skip = skip_multibyte_char( *s );
|
||||||
return(True);
|
if( skip != 0 )
|
||||||
s++;
|
s += skip;
|
||||||
|
else {
|
||||||
|
if (islower(*s))
|
||||||
|
return(True);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(False);
|
return(False);
|
||||||
@@ -1953,9 +1963,14 @@ int count_chars(char *s,char c)
|
|||||||
{
|
{
|
||||||
while (*s)
|
while (*s)
|
||||||
{
|
{
|
||||||
if (*s == c)
|
int skip = skip_multibyte_char( *s );
|
||||||
count++;
|
if( skip != 0 )
|
||||||
s++;
|
s += skip;
|
||||||
|
else {
|
||||||
|
if (*s == c)
|
||||||
|
count++;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return(count);
|
return(count);
|
||||||
@@ -2966,12 +2981,12 @@ BOOL string_sub(char *s,char *pattern,char *insert)
|
|||||||
return(ret);
|
return(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************
|
/*********************************************************
|
||||||
* Recursive routine that is called by mask_match.
|
* Recursive routine that is called by mask_match.
|
||||||
* Does the actual matching.
|
* Does the actual matching. Returns True if matched,
|
||||||
|
* False if failed.
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
|
|
||||||
BOOL do_match(char *str, char *regexp, int case_sig)
|
BOOL do_match(char *str, char *regexp, int case_sig)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
@@ -2984,48 +2999,61 @@ BOOL do_match(char *str, char *regexp, int case_sig)
|
|||||||
|
|
||||||
case '*':
|
case '*':
|
||||||
/* Look for a character matching
|
/* Look for a character matching
|
||||||
the one after the '*' */
|
the one after the '*' */
|
||||||
p++;
|
p++;
|
||||||
if(!*p)
|
if(!*p)
|
||||||
return True; /* Automatic match */
|
return True; /* Automatic match */
|
||||||
while(*str) {
|
while(*str) {
|
||||||
while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
|
while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
|
||||||
str++;
|
str++;
|
||||||
if(do_match(str,p,case_sig))
|
/* Now eat all characters that match, as
|
||||||
return True;
|
we want the *last* character to match. */
|
||||||
if(!*str)
|
while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str))))
|
||||||
return False;
|
str++;
|
||||||
else
|
str--; /* We've eaten the match char after the '*' */
|
||||||
str++;
|
if(do_match(str,p,case_sig)) {
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
if(!*str) {
|
||||||
|
return False;
|
||||||
|
} else {
|
||||||
|
str++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return False;
|
return False;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if(case_sig) {
|
if(case_sig) {
|
||||||
if(*str != *p)
|
if(*str != *p) {
|
||||||
return False;
|
return False;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if(toupper(*str) != toupper(*p))
|
if(toupper(*str) != toupper(*p)) {
|
||||||
return False;
|
return False;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
str++, p++;
|
str++, p++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!*p && !*str)
|
if(!*p && !*str)
|
||||||
return True;
|
return True;
|
||||||
|
|
||||||
if (!*p && str[0] == '.' && str[1] == 0)
|
if (!*p && str[0] == '.' && str[1] == 0) {
|
||||||
return(True);
|
return(True);
|
||||||
|
}
|
||||||
|
|
||||||
if (!*str && *p == '?')
|
if (!*str && *p == '?') {
|
||||||
{
|
while (*p == '?')
|
||||||
while (*p == '?') p++;
|
p++;
|
||||||
return(!*p);
|
return(!*p);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!*str && (*p == '*' && p[1] == '\0'))
|
if(!*str && (*p == '*' && p[1] == '\0')) {
|
||||||
return True;
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3034,98 +3062,204 @@ BOOL do_match(char *str, char *regexp, int case_sig)
|
|||||||
* Routine to match a given string with a regexp - uses
|
* Routine to match a given string with a regexp - uses
|
||||||
* simplified regexp that takes * and ? only. Case can be
|
* simplified regexp that takes * and ? only. Case can be
|
||||||
* significant or not.
|
* significant or not.
|
||||||
|
* The 8.3 handling was rewritten by Ums Harald <Harald.Ums@pro-sieben.de>
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
|
|
||||||
BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
|
BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
pstring p1, p2;
|
pstring t_pattern, t_filename, te_pattern, te_filename;
|
||||||
fstring ebase,eext,sbase,sext;
|
fstring ebase,eext,sbase,sext;
|
||||||
|
|
||||||
BOOL matched;
|
BOOL matched = False;
|
||||||
|
|
||||||
/* Make local copies of str and regexp */
|
/* Make local copies of str and regexp */
|
||||||
StrnCpy(p1,regexp,sizeof(pstring)-1);
|
pstrcpy(t_pattern,regexp);
|
||||||
StrnCpy(p2,str,sizeof(pstring)-1);
|
pstrcpy(t_filename,str);
|
||||||
|
|
||||||
if (!strchr(p2,'.')) {
|
if(trans2 && is_8_3(t_pattern,False) && is_8_3(t_filename,False))
|
||||||
pstrcat(p2,".");
|
trans2 = False;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (!strchr(p1,'.')) {
|
|
||||||
pstrcat(p1,".");
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (strchr(p1,'.'))
|
if (!strchr(t_filename,'.')) {
|
||||||
{
|
pstrcat(t_filename,".");
|
||||||
string_sub(p1,"*.*","*");
|
}
|
||||||
string_sub(p1,".*","*");
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Remove any *? and ** as they are meaningless */
|
/* Remove any *? and ** as they are meaningless */
|
||||||
for(p = p1; *p; p++)
|
string_sub(t_pattern, "*?", "*");
|
||||||
while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
|
string_sub(t_pattern, "**", "*");
|
||||||
(void)pstrcpy( &p[1], &p[2]);
|
|
||||||
|
|
||||||
if (strequal(p1,"*")) return(True);
|
if (strequal(t_pattern,"*"))
|
||||||
|
return(True);
|
||||||
|
|
||||||
DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
|
DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", t_filename, t_pattern, case_sig));
|
||||||
|
|
||||||
if (trans2) {
|
|
||||||
fstrcpy(ebase,p1);
|
|
||||||
fstrcpy(sbase,p2);
|
|
||||||
} else {
|
|
||||||
if ((p=strrchr(p1,'.'))) {
|
|
||||||
*p = 0;
|
|
||||||
fstrcpy(ebase,p1);
|
|
||||||
fstrcpy(eext,p+1);
|
|
||||||
} else {
|
|
||||||
fstrcpy(ebase,p1);
|
|
||||||
eext[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strequal(p2,".") && !strequal(p2,"..") && (p=strrchr(p2,'.'))) {
|
|
||||||
*p = 0;
|
|
||||||
fstrcpy(sbase,p2);
|
|
||||||
fstrcpy(sext,p+1);
|
|
||||||
} else {
|
|
||||||
fstrcpy(sbase,p2);
|
|
||||||
fstrcpy(sext,"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(trans2) {
|
if(trans2) {
|
||||||
/*
|
/*
|
||||||
* Match each component of the path, split up by '.'
|
* Match each component of the regexp, split up by '.'
|
||||||
* characters.
|
* characters.
|
||||||
*/
|
*/
|
||||||
char *fp, *rp, *cp2, *cp1;
|
char *fp, *rp, *cp2, *cp1;
|
||||||
BOOL last_wcard_was_star = False;
|
BOOL last_wcard_was_star = False;
|
||||||
matched = False;
|
int num_path_components, num_regexp_components;
|
||||||
for( cp1 = ebase, cp2 = sbase; cp1;) {
|
|
||||||
fp = strchr(cp2, '.');
|
|
||||||
if(fp)
|
|
||||||
*fp = '\0';
|
|
||||||
rp = strchr(cp1, '.');
|
|
||||||
if(rp)
|
|
||||||
*rp = '\0';
|
|
||||||
|
|
||||||
if(cp1[strlen(cp1)-1] == '*')
|
pstrcpy(te_pattern,t_pattern);
|
||||||
last_wcard_was_star = True;
|
pstrcpy(te_filename,t_filename);
|
||||||
else
|
/*
|
||||||
last_wcard_was_star = False;
|
* Remove multiple "*." patterns.
|
||||||
if(!do_match(cp2, cp1, case_sig))
|
*/
|
||||||
break;
|
string_sub(te_pattern, "*.*.", "*.");
|
||||||
cp2 = fp ? fp + 1 : "";
|
num_regexp_components = count_chars(te_pattern, '.');
|
||||||
cp1 = rp ? rp + 1 : NULL;
|
num_path_components = count_chars(te_filename, '.');
|
||||||
}
|
|
||||||
if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star))
|
/*
|
||||||
matched = True;
|
* Check for special 'hack' case of "DIR a*z". - needs to match a.b.c...z
|
||||||
|
*/
|
||||||
|
if(num_regexp_components == 0)
|
||||||
|
matched = do_match( te_filename, te_pattern, case_sig);
|
||||||
|
else {
|
||||||
|
for( cp1 = te_pattern, cp2 = te_filename; cp1;) {
|
||||||
|
fp = strchr(cp2, '.');
|
||||||
|
if(fp)
|
||||||
|
*fp = '\0';
|
||||||
|
rp = strchr(cp1, '.');
|
||||||
|
if(rp)
|
||||||
|
*rp = '\0';
|
||||||
|
|
||||||
|
if(cp1[strlen(cp1)-1] == '*')
|
||||||
|
last_wcard_was_star = True;
|
||||||
|
else
|
||||||
|
last_wcard_was_star = False;
|
||||||
|
|
||||||
|
if(!do_match(cp2, cp1, case_sig))
|
||||||
|
break;
|
||||||
|
|
||||||
|
cp1 = rp ? rp + 1 : NULL;
|
||||||
|
cp2 = fp ? fp + 1 : "";
|
||||||
|
|
||||||
|
if(last_wcard_was_star || ((cp1 != NULL) && (*cp1 == '*'))) {
|
||||||
|
/* Eat the extra path components. */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < num_path_components - num_regexp_components; i++) {
|
||||||
|
fp = strchr(cp2, '.');
|
||||||
|
if(fp)
|
||||||
|
*fp = '\0';
|
||||||
|
|
||||||
|
if(do_match( cp2, cp1, case_sig)) {
|
||||||
|
cp1 = rp ? rp + 1 : NULL;
|
||||||
|
cp2 = fp ? fp + 1 : "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cp2 = fp + 1;
|
||||||
|
}
|
||||||
|
num_path_components -= i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star))
|
||||||
|
matched = True;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
matched = do_match(sbase,ebase,case_sig) && do_match(sext,eext,case_sig);
|
|
||||||
|
/* -------------------------------------------------
|
||||||
|
* Behaviour of Win95
|
||||||
|
* for 8.3 filenames and 8.3 Wildcards
|
||||||
|
* -------------------------------------------------
|
||||||
|
*/
|
||||||
|
if (strequal (t_filename, ".")) {
|
||||||
|
/*
|
||||||
|
* Patterns: *.* *. ?. ? are valid
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") ||
|
||||||
|
strequal(t_pattern, "?.") || strequal(t_pattern, "?"))
|
||||||
|
matched = True;
|
||||||
|
} else if (strequal (t_filename, "..")) {
|
||||||
|
/*
|
||||||
|
* Patterns: *.* *. ?. ? *.? are valid
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if(strequal(t_pattern, "*.*") || strequal(t_pattern, "*.") ||
|
||||||
|
strequal(t_pattern, "?.") || strequal(t_pattern, "?") ||
|
||||||
|
strequal(t_pattern, "*.?") || strequal(t_pattern, "?.*"))
|
||||||
|
matched = True;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if ((p = strrchr (t_pattern, '.'))) {
|
||||||
|
/*
|
||||||
|
* Wildcard has a suffix.
|
||||||
|
*/
|
||||||
|
*p = 0;
|
||||||
|
fstrcpy (ebase, t_pattern);
|
||||||
|
if (p[1]) {
|
||||||
|
fstrcpy (eext, p + 1);
|
||||||
|
} else {
|
||||||
|
/* pattern ends in DOT: treat as if there is no DOT */
|
||||||
|
*eext = 0;
|
||||||
|
if (strequal (ebase, "*"))
|
||||||
|
return (True);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* No suffix for wildcard.
|
||||||
|
*/
|
||||||
|
fstrcpy (ebase, t_pattern);
|
||||||
|
eext[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = strrchr (t_filename, '.');
|
||||||
|
if (p && (p[1] == 0) ) {
|
||||||
|
/*
|
||||||
|
* Filename has an extension of '.' only.
|
||||||
|
*/
|
||||||
|
*p = 0; /* nuke dot at end of string */
|
||||||
|
p = 0; /* and treat it as if there is no extension */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p) {
|
||||||
|
/*
|
||||||
|
* Filename has an extension.
|
||||||
|
*/
|
||||||
|
*p = 0;
|
||||||
|
fstrcpy (sbase, t_filename);
|
||||||
|
fstrcpy (sext, p + 1);
|
||||||
|
if (*eext) {
|
||||||
|
matched = do_match(sbase, ebase, case_sig)
|
||||||
|
&& do_match(sext, eext, case_sig);
|
||||||
|
} else {
|
||||||
|
/* pattern has no extension */
|
||||||
|
/* Really: match complete filename with pattern ??? means exactly 3 chars */
|
||||||
|
matched = do_match(str, ebase, case_sig);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Filename has no extension.
|
||||||
|
*/
|
||||||
|
fstrcpy (sbase, t_filename);
|
||||||
|
fstrcpy (sext, "");
|
||||||
|
if (*eext) {
|
||||||
|
/* pattern has extension */
|
||||||
|
matched = do_match(sbase, ebase, case_sig)
|
||||||
|
&& do_match(sext, eext, case_sig);
|
||||||
|
} else {
|
||||||
|
matched = do_match(sbase, ebase, case_sig);
|
||||||
|
#ifdef EMULATE_WEIRD_W95_MATCHING
|
||||||
|
/*
|
||||||
|
* Even Microsoft has some problems
|
||||||
|
* Behaviour Win95 -> local disk
|
||||||
|
* is different from Win95 -> smb drive from Nt 4.0
|
||||||
|
* This branch would reflect the Win95 local disk behaviour
|
||||||
|
*/
|
||||||
|
if (!matched) {
|
||||||
|
/* a? matches aa and a in w95 */
|
||||||
|
fstrcat (sbase, ".");
|
||||||
|
matched = do_match(sbase, ebase, case_sig);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(8,("mask_match returning %d\n", matched));
|
DEBUG(8,("mask_match returning %d\n", matched));
|
||||||
@@ -3133,8 +3267,6 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
|
|||||||
return matched;
|
return matched;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
become a daemon, discarding the controlling terminal
|
become a daemon, discarding the controlling terminal
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
Reference in New Issue
Block a user