1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-12 12:23:50 +03:00

- removed all our old wildcard matching code and replaced it with a

call to ms_fnmatch(). This also removes all the Win9X semantics stuff
and a bunch of other associated cruft.

- moved the stat cache code into statcache.c

- fixed the uint16 alignment requirements of ascii_to_unistr() and
  unistr_to_ascii()

- trans2 SMB_FIND_FILE_BOTH_DIRECTORY_INFO returns the short name as
  unicode always (at least thats what NT4 does)

- fixed some errors in the in-memory tdb code. Still ugly, but doesn't
  crash as much
This commit is contained in:
Andrew Tridgell
-
parent cc9e007cdf
commit 03e9cea004
15 changed files with 391 additions and 975 deletions

View File

@@ -90,9 +90,6 @@ pstring global_myname = "";
fstring global_myworkgroup = "";
char **my_netbios_names;
static char *filename_dos(char *path,char *buf);
/****************************************************************************
find a suitable temporary directory. The result should be copied immediately
@@ -543,85 +540,6 @@ BOOL reduce_name(char *s,char *dir,BOOL widelinks)
#endif
}
/****************************************************************************
expand some *s
****************************************************************************/
static void expand_one(char *Mask,int len)
{
char *p1;
while ((p1 = strchr(Mask,'*')) != NULL)
{
int lfill = (len+1) - strlen(Mask);
int l1= (p1 - Mask);
pstring tmp;
pstrcpy(tmp,Mask);
memset(tmp+l1,'?',lfill);
pstrcpy(tmp + l1 + lfill,Mask + l1 + 1);
pstrcpy(Mask,tmp);
}
}
/****************************************************************************
expand a wildcard expression, replacing *s with ?s
****************************************************************************/
void expand_mask(char *Mask,BOOL doext)
{
pstring mbeg,mext;
pstring dirpart;
pstring filepart;
BOOL hasdot = False;
char *p1;
BOOL absolute = (*Mask == '\\');
*mbeg = *mext = *dirpart = *filepart = 0;
/* parse the directory and filename */
if (strchr(Mask,'\\'))
split_at_last_component(Mask,dirpart,'\\',NULL);
filename_dos(Mask,filepart);
pstrcpy(mbeg,filepart);
if ((p1 = strchr(mbeg,'.')) != NULL)
{
hasdot = True;
*p1 = 0;
p1++;
pstrcpy(mext,p1);
}
else
{
pstrcpy(mext,"");
if (strlen(mbeg) > 8)
{
pstrcpy(mext,mbeg + 8);
mbeg[8] = 0;
}
}
if (*mbeg == 0)
pstrcpy(mbeg,"????????");
if ((*mext == 0) && doext && !hasdot)
pstrcpy(mext,"???");
if (strequal(mbeg,"*") && *mext==0)
pstrcpy(mext,"*");
/* expand *'s */
expand_one(mbeg,8);
if (*mext)
expand_one(mext,3);
pstrcpy(Mask,dirpart);
if (*dirpart || absolute) pstrcat(Mask,"\\");
pstrcat(Mask,mbeg);
pstrcat(Mask,".");
pstrcat(Mask,mext);
DEBUG(6,("Mask expanded to [%s]\n",Mask));
}
/****************************************************************************
make a dir struct
@@ -818,502 +736,6 @@ void msleep(int t)
}
/*********************************************************
* Recursive routine that is called by unix_mask_match.
* Does the actual matching. This is the 'original code'
* used by the unix matcher.
*********************************************************/
BOOL unix_do_match(char *str, char *regexp, BOOL case_sig)
{
char *p;
for( p = regexp; *p && *str; ) {
switch(*p) {
case '?':
str++; p++;
break;
case '*':
/*
* Look for a character matching
* the one after the '*'.
*/
p++;
if(!*p)
return True; /* Automatic match */
while(*str) {
while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
str++;
/*
* Patch from weidel@multichart.de. In the case of the regexp
* '*XX*' we want to ensure there are at least 2 'X' characters
* in the filename after the '*' for a match to be made.
*/
{
int matchcount=0;
/*
* Eat all the characters that match, but count how many there were.
*/
while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str)))) {
str++;
matchcount++;
}
/*
* Now check that if the regexp had n identical characters that
* matchcount had at least that many matches.
*/
while (( *(p+1) && (case_sig ? (*(p+1) == *p) : (toupper(*(p+1))==toupper(*p))))) {
p++;
matchcount--;
}
if ( matchcount <= 0 ) {
return False;
}
}
str--; /* We've eaten the match char after the '*' */
if(unix_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;
} else {
if(toupper(*str) != toupper(*p))
return False;
}
str++, p++;
break;
}
}
if(!*p && !*str)
return True;
if (!*p && str[0] == '.' && str[1] == 0)
return(True);
if (!*str && *p == '?')
{
while (*p == '?') p++;
return(!*p);
}
if(!*str && (*p == '*' && p[1] == '\0'))
return True;
return False;
}
/*********************************************************
* Routine to match a given string with a regexp - uses
* simplified regexp that takes * and ? only. Case can be
* significant or not.
* This is the 'original code' used by the unix matcher.
*********************************************************/
static BOOL unix_mask_match(char *str, char *regexp, BOOL case_sig)
{
char *p;
pstring p1, p2;
fstring ebase,sbase;
BOOL matched;
/* Make local copies of str and regexp */
StrnCpy(p1,regexp,sizeof(pstring)-1);
StrnCpy(p2,str,sizeof(pstring)-1);
/* 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);
DEBUG(8,("unix_mask_match str=<%s> regexp=<%s>, case_sig = %d\n", p2, p1, case_sig));
fstrcpy(ebase,p1);
fstrcpy(sbase,p2);
matched = unix_do_match(sbase,ebase,case_sig);
DEBUG(8,("unix_mask_match returning %d\n", matched));
return matched;
}
/*********************************************************
* Recursive routine that is called by mask_match.
* Does the actual matching. Returns True if matched,
* False if failed. This is the 'new' NT style matcher.
* The win9x_semantics parameter is needed as Win9x matching
* is *actually different*. In Win9x, trailing '?' characters
* will only match the *exact* number of characters. Under
* DOS and NT they match any number. This makes no
* sense.....
*********************************************************/
static BOOL do_match(char *str, char *regexp, int case_sig, BOOL win9x_semantics)
{
char *p;
for( p = regexp; *p && *str; ) {
switch(*p) {
case '?':
str++; p++;
break;
case '*':
/* Look for a character matching
the one after the '*' */
p++;
if(!*p)
return True; /* Automatic match */
while(*str) {
while(*str && (case_sig ? (*p != *str) : (toupper(*p)!=toupper(*str))))
str++;
/*
* Patch from weidel@multichart.de. In the case of the regexp
* '*XX*' we want to ensure there are at least 2 'X' characters
* in the filename after the '*' for a match to be made.
*/
{
int matchcount=0;
/*
* Eat all the characters that match, but count how many there were.
*/
while(*str && (case_sig ? (*p == *str) : (toupper(*p)==toupper(*str)))) {
str++;
matchcount++;
}
/*
* Now check that if the regexp had n identical characters that
* matchcount had at least that many matches.
*/
while (( *(p+1) && (case_sig ? (*(p+1) == *p) : (toupper(*(p+1))==toupper(*p))))) {
p++;
matchcount--;
}
if ( matchcount <= 0 ) {
return False;
}
}
str--; /* We've eaten the match char after the '*' */
if(do_match(str,p,case_sig,win9x_semantics)) {
return True;
}
if(!*str) {
return False;
} else {
str++;
}
}
return False;
default:
if(case_sig) {
if(*str != *p) {
return False;
}
} else {
if(toupper(*str) != toupper(*p)) {
return False;
}
}
str++, p++;
break;
}
}
if(!*p && !*str)
return True;
if (!*p && str[0] == '.' && str[1] == 0) {
return(True);
}
if (!win9x_semantics) {
if (!*str && *p == '?') {
while (*p == '?')
p++;
return(!*p);
}
}
if(!*str && (*p == '*' && p[1] == '\0')) {
return True;
}
return False;
}
/*********************************************************
* 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>
* This is the new 'NT style' matcher.
*********************************************************/
BOOL mask_match(char *str, char *regexp, BOOL case_sig, BOOL trans2)
{
char *p;
pstring t_pattern, t_filename, te_pattern, te_filename;
fstring ebase,eext,sbase,sext;
BOOL matched = False;
BOOL win9x_semantics = (get_remote_arch() == RA_WIN95) && trans2;
/* special case - if it is exactly the same then it always matches! */
if(exact_match(str, regexp, case_sig))
return True;
/* Make local copies of str and regexp */
pstrcpy(t_pattern,regexp);
pstrcpy(t_filename,str);
if(trans2) {
/* a special case for 16 bit apps */
if (strequal(t_pattern,"????????.???"))
pstrcpy(t_pattern,"*");
#if 0
/*
* Handle broken clients that send us old 8.3 format.
*/
pstring_sub(t_pattern,"????????","*");
pstring_sub(t_pattern,".???",".*");
#endif
}
#if 0
/*
* Not sure if this is a good idea. JRA.
*/
if(trans2 && is_8_3(t_pattern,False) && is_8_3(t_filename,False))
trans2 = False;
#endif
#if 0
if (!strchr(t_filename,'.')) {
pstrcat(t_filename,".");
}
#endif
/* Remove any *? and ** as they are meaningless */
for(p = t_pattern; *p; p++)
while( *p == '*' && (p[1] == '?' || p[1] == '*'))
(void)pstrcpy( &p[1], &p[2]);
if (strequal(t_pattern,"*"))
return(True);
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 regexp, split up by '.'
* characters.
*/
char *fp, *rp, *cp2, *cp1;
BOOL last_wcard_was_star = False;
int num_path_components, num_regexp_components;
pstrcpy(te_pattern,t_pattern);
pstrcpy(te_filename,t_filename);
/*
* Remove multiple "*." patterns.
*/
pstring_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, win9x_semantics);
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[0] && cp1[strlen(cp1)-1] == '*')
last_wcard_was_star = True;
else
last_wcard_was_star = False;
if(!do_match(cp2, cp1, case_sig, win9x_semantics))
break;
/*
* Ugly ! Special case for Win9x *only*. If filename is XXXX and pattern extension
* is '*' or all '?' then disallow match.
*/
if (win9x_semantics) {
if (*cp2 == '\0' && str_is_all(cp1, '?'))
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((cp1 != NULL) && do_match( cp2, cp1, case_sig, win9x_semantics)) {
cp2 = fp ? fp + 1 : "";
break;
}
cp2 = fp ? fp + 1 : "";
}
num_path_components -= i;
}
}
if(cp1 == NULL && ((*cp2 == '\0') || last_wcard_was_star))
matched = True;
}
} else {
/* -------------------------------------------------
* 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, "?.") || 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, "*.?") || 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, False)
&& do_match(sext, eext, case_sig, False);
} else {
/* pattern has no extension */
/* Really: match complete filename with pattern ??? means exactly 3 chars */
matched = do_match(str, ebase, case_sig, False);
}
} else {
/*
* Filename has no extension.
*/
fstrcpy (sbase, t_filename);
fstrcpy (sext, "");
if (*eext) {
/* pattern has extension */
matched = do_match(sbase, ebase, case_sig, False)
&& do_match(sext, eext, case_sig, False);
} else {
matched = do_match(sbase, ebase, case_sig, False);
#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, False);
}
#endif
}
}
}
}
DEBUG(8,("mask_match returning %d\n", matched));
return matched;
}
/****************************************************************************
become a daemon, discarding the controlling terminal
****************************************************************************/
@@ -1419,24 +841,6 @@ this is a version of setbuffer() for those machines that only have setvbuf
}
#endif
/****************************************************************************
parse out a filename from a path name. Assumes dos style filenames.
****************************************************************************/
static char *filename_dos(char *path,char *buf)
{
char *p = strrchr(path,'\\');
if (!p)
pstrcpy(buf,path);
else
pstrcpy(buf,p+1);
return(buf);
}
/****************************************************************************
expand a pointer to be a particular size
****************************************************************************/
@@ -1961,12 +1365,7 @@ BOOL is_in_path(char *name, name_compare_entry *namelist)
{
if(namelist->is_wild)
{
/*
* Look for a wildcard match. Use the old
* 'unix style' mask match, rather than the
* new NT one.
*/
if (unix_mask_match(last_component, namelist->name, case_sensitive))
if (mask_match(last_component, namelist->name, case_sensitive))
{
DEBUG(8,("is_in_path: mask match succeeded\n"));
return True;
@@ -2067,8 +1466,7 @@ void set_namearray(name_compare_entry **ppname_array, char *namelist)
if(name_end == NULL)
break;
(*ppname_array)[i].is_wild = ((strchr( nameptr, '?')!=NULL) ||
(strchr( nameptr, '*')!=NULL));
(*ppname_array)[i].is_wild = ms_has_wild(nameptr);
if(((*ppname_array)[i].name = strdup(nameptr)) == NULL)
{
DEBUG(0,("set_namearray: malloc fail (1)\n"));
@@ -2653,7 +2051,58 @@ char *parent_dirname(const char *path)
}
/*******************************************************************
determine if a pattern contains any Microsoft wildcard characters
*******************************************************************/
BOOL ms_has_wild(char *s)
{
char c;
while ((c = *s++)) {
switch (c) {
case '*':
case '?':
case '<':
case '>':
case '"':
return True;
}
}
return False;
}
/*******************************************************************
a wrapper that handles case sensitivity and the special handling
of the ".." name
case_sensitive is a boolean
*******************************************************************/
BOOL mask_match(char *string, char *pattern, BOOL case_sensitive)
{
fstring p2, s2;
if (strcmp(string,"..") == 0) string = ".";
if (strcmp(pattern,".") == 0) return False;
if (case_sensitive) {
return ms_fnmatch(pattern, string) == 0;
}
fstrcpy(p2, pattern);
fstrcpy(s2, string);
strlower(p2);
strlower(s2);
return ms_fnmatch(p2, s2) == 0;
}
#ifdef __INSURE__
/*******************************************************************
This routine is a trick to immediately catch errors when debugging
with insure. A xterm with a gdb is popped up when insure catches
a error. It is Linux specific.
********************************************************************/
int _Insure_trap_error(int a1, int a2, int a3, int a4, int a5, int a6)
{
static int (*fn)();