From ad53f02511506e75f4f656b4164e12da4a7aafe7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 27 May 1998 22:48:22 +0000 Subject: Newly re-written do_match and mask_match functions, with the help of Ums Harald , 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 94e3f0d9b48c1ac6d9235eb6600aff1c47e024bc) --- source3/include/proto.h | 1 + source3/lib/util.c | 338 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 236 insertions(+), 103 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index 3086c6cd24..44821405d4 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -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); diff --git a/source3/lib/util.c b/source3/lib/util.c index 98cd150d7f..dc8619cdc6 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -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 *********************************************************/ + 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); - - if (!strchr(p2,'.')) { - pstrcat(p2,"."); - } + pstrcpy(t_pattern,regexp); + pstrcpy(t_filename,str); -/* - 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]); - - if (strequal(p1,"*")) return(True); + string_sub(t_pattern, "*?", "*"); + string_sub(t_pattern, "**", "*"); - DEBUG(8,("mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig)); + if (strequal(t_pattern,"*")) + return(True); - 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'; - - 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; + int num_path_components, num_regexp_components; + + 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 ****************************************************************************/ -- cgit