1
0
mirror of https://github.com/samba-team/samba.git synced 2025-08-24 21:49:29 +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 used to be commit 94e3f0d9b4)
This commit is contained in:
Jeremy Allison
1998-05-27 22:48:22 +00:00
parent 8e914e55c0
commit ad53f02511
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);
BOOL string_set(char **dest,char *src);
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 mask_match(char *str, char *regexp, int case_sig,BOOL trans2);
void become_daemon(void);

View File

@ -1858,9 +1858,14 @@ BOOL strhasupper(char *s)
else
#endif /* KANJI_WIN95_COMPATIBILITY */
{
if (isupper(*s))
return(True);
s++;
int skip = skip_multibyte_char( *s );
if( skip != 0 )
s += skip;
else {
if (isupper(*s))
return(True);
s++;
}
}
}
return(False);
@ -1908,9 +1913,14 @@ BOOL strhaslower(char *s)
else
#endif /* KANJI_WIN95_COMPATIBILITY */
{
if (islower(*s))
return(True);
s++;
int skip = skip_multibyte_char( *s );
if( skip != 0 )
s += skip;
else {
if (islower(*s))
return(True);
s++;
}
}
}
return(False);
@ -1953,9 +1963,14 @@ int count_chars(char *s,char c)
{
while (*s)
{
if (*s == c)
count++;
s++;
int skip = skip_multibyte_char( *s );
if( skip != 0 )
s += skip;
else {
if (*s == c)
count++;
s++;
}
}
}
return(count);
@ -2966,12 +2981,12 @@ BOOL string_sub(char *s,char *pattern,char *insert)
return(ret);
}
/*********************************************************
* 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)
{
char *p;
@ -2984,48 +2999,61 @@ BOOL do_match(char *str, char *regexp, int case_sig)
case '*':
/* Look for a character matching
the one after the '*' */
the one after the '*' */
p++;
if(!*p)
return True; /* Automatic match */
return True; /* Automatic match */
while(*str) {
while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
str++;
if(do_match(str,p,case_sig))
return True;
if(!*str)
return False;
else
str++;
while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
str++;
/* Now eat all characters that match, as
we want the *last* character to match. */
while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*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;
default:
if(case_sig) {
if(*str != *p)
return False;
if(*str != *p) {
return False;
}
} else {
if(toupper(*str) != toupper(*p))
return False;
if(toupper(*str) != toupper(*p)) {
return False;
}
}
str++, p++;
break;
}
}
if(!*p && !*str)
return True;
if (!*p && str[0] == '.' && str[1] == 0)
if (!*p && str[0] == '.' && str[1] == 0) {
return(True);
}
if (!*str && *p == '?')
{
while (*p == '?') p++;
return(!*p);
}
if (!*str && *p == '?') {
while (*p == '?')
p++;
return(!*p);
}
if(!*str && (*p == '*' && p[1] == '\0'))
if(!*str && (*p == '*' && p[1] == '\0')) {
return True;
}
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
* simplified regexp that takes * and ? only. Case can be
* 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)
{
char *p;
pstring p1, p2;
pstring t_pattern, t_filename, te_pattern, te_filename;
fstring ebase,eext,sbase,sext;
BOOL matched;
BOOL matched = False;
/* Make local copies of str and regexp */
StrnCpy(p1,regexp,sizeof(pstring)-1);
StrnCpy(p2,str,sizeof(pstring)-1);
pstrcpy(t_pattern,regexp);
pstrcpy(t_filename,str);
if (!strchr(p2,'.')) {
pstrcat(p2,".");
}
/*
if (!strchr(p1,'.')) {
pstrcat(p1,".");
}
*/
if(trans2 && is_8_3(t_pattern,False) && is_8_3(t_filename,False))
trans2 = False;
#if 0
if (strchr(p1,'.'))
{
string_sub(p1,"*.*","*");
string_sub(p1,".*","*");
}
if (!strchr(t_filename,'.')) {
pstrcat(t_filename,".");
}
#endif
/* Remove any *? and ** as they are meaningless */
for(p = p1; *p; p++)
while( *p == '*' && (p[1] == '?' ||p[1] == '*'))
(void)pstrcpy( &p[1], &p[2]);
string_sub(t_pattern, "*?", "*");
string_sub(t_pattern, "**", "*");
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));
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,"");
}
}
DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", t_filename, t_pattern, case_sig));
if(trans2) {
/*
* Match each component of the path, split up by '.'
* Match each component of the regexp, split up by '.'
* characters.
*/
char *fp, *rp, *cp2, *cp1;
BOOL last_wcard_was_star = False;
matched = False;
for( cp1 = ebase, cp2 = sbase; cp1;) {
fp = strchr(cp2, '.');
if(fp)
*fp = '\0';
rp = strchr(cp1, '.');
if(rp)
*rp = '\0';
int num_path_components, num_regexp_components;
if(cp1[strlen(cp1)-1] == '*')
last_wcard_was_star = True;
else
last_wcard_was_star = False;
if(!do_match(cp2, cp1, case_sig))
break;
cp2 = fp ? fp + 1 : "";
cp1 = rp ? rp + 1 : NULL;
}
if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star))
matched = True;
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, '.');
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 {
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));
@ -3133,8 +3267,6 @@ BOOL mask_match(char *str, char *regexp, int case_sig,BOOL trans2)
return matched;
}
/****************************************************************************
become a daemon, discarding the controlling terminal
****************************************************************************/