1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-18 08:23:51 +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:
Jeremy Allison
-
parent 3bc0d700d1
commit 94e3f0d9b4
2 changed files with 235 additions and 102 deletions

View File

@@ -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);

View File

@@ -1858,11 +1858,16 @@ BOOL strhasupper(char *s)
else else
#endif /* KANJI_WIN95_COMPATIBILITY */ #endif /* KANJI_WIN95_COMPATIBILITY */
{ {
int skip = skip_multibyte_char( *s );
if( skip != 0 )
s += skip;
else {
if (isupper(*s)) if (isupper(*s))
return(True); return(True);
s++; s++;
} }
} }
}
return(False); return(False);
} }
@@ -1908,11 +1913,16 @@ BOOL strhaslower(char *s)
else else
#endif /* KANJI_WIN95_COMPATIBILITY */ #endif /* KANJI_WIN95_COMPATIBILITY */
{ {
int skip = skip_multibyte_char( *s );
if( skip != 0 )
s += skip;
else {
if (islower(*s)) if (islower(*s))
return(True); return(True);
s++; s++;
} }
} }
}
return(False); return(False);
} }
@@ -1953,11 +1963,16 @@ int count_chars(char *s,char c)
{ {
while (*s) while (*s)
{ {
int skip = skip_multibyte_char( *s );
if( skip != 0 )
s += skip;
else {
if (*s == c) if (*s == c)
count++; count++;
s++; 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;
@@ -2991,41 +3006,54 @@ BOOL do_match(char *str, char *regexp, int case_sig)
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;
else
str++; str++;
str--; /* We've eaten the match char after the '*' */
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,78 +3062,64 @@ 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;) {
pstrcpy(te_pattern,t_pattern);
pstrcpy(te_filename,t_filename);
/*
* Remove multiple "*." patterns.
*/
string_sub(te_pattern, "*.*.", "*.");
num_regexp_components = count_chars(te_pattern, '.');
num_path_components = count_chars(te_filename, '.');
/*
* 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, '.'); fp = strchr(cp2, '.');
if(fp) if(fp)
*fp = '\0'; *fp = '\0';
@@ -3117,15 +3131,135 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
last_wcard_was_star = True; last_wcard_was_star = True;
else else
last_wcard_was_star = False; last_wcard_was_star = False;
if(!do_match(cp2, cp1, case_sig)) if(!do_match(cp2, cp1, case_sig))
break; break;
cp2 = fp ? fp + 1 : "";
cp1 = rp ? rp + 1 : NULL; 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)) if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star))
matched = True; 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
****************************************************************************/ ****************************************************************************/