mangling + wildcards

Jeremy Allison jra at samba.org
Wed Sep 13 15:33:07 GMT 2006


On Mon, Sep 11, 2006 at 06:17:07PM -0700, Jeremy Allison wrote:
> 
> Ok, this is a subtle one involving bugs in smbd/dir.c
> (optimisation error :-) and in smbd/trans2.c. I'll
> fix this..... Expect a patch once I've reached my
> travel destination :-).

Here is the fix for the bug. Please test this out and
get back to me.

Thanks,

	Jeremy.
-------------- next part --------------
Index: smbd/trans2.c
===================================================================
--- smbd/trans2.c	(revision 18470)
+++ smbd/trans2.c	(working copy)
@@ -957,16 +957,16 @@
  Case can be significant or not.
 **********************************************************/
 
-static BOOL exact_match(char *str,char *mask, BOOL case_sig) 
+static BOOL exact_match(connection_struct *conn, char *str, char *mask)
 {
 	if (mask[0] == '.' && mask[1] == 0)
 		return False;
-	if (case_sig)	
+	if (conn->case_sensitive)
 		return strcmp(str,mask)==0;
 	if (StrCaseCmp(str,mask) != 0) {
 		return False;
 	}
-	if (ms_has_wild(str)) {
+	if (dptr_has_wild(conn->dirptr)) {
 		return False;
 	}
 	return True;
@@ -1132,7 +1132,7 @@
 
 		pstrcpy(fname,dname);      
 
-		if(!(got_match = *got_exact_match = exact_match(fname, mask, conn->case_sensitive)))
+		if(!(got_match = *got_exact_match = exact_match(conn, fname, mask)))
 			got_match = mask_match(fname, mask, conn->case_sensitive);
 
 		if(!got_match && check_mangled_names &&
@@ -1148,7 +1148,7 @@
 			pstring newname;
 			pstrcpy( newname, fname);
 			mangle_map( newname, True, False, conn->params);
-			if(!(got_match = *got_exact_match = exact_match(newname, mask, conn->case_sensitive)))
+			if(!(got_match = *got_exact_match = exact_match(conn, newname, mask)))
 				got_match = mask_match(newname, mask, conn->case_sensitive);
 		}
 
Index: smbd/dir.c
===================================================================
--- smbd/dir.c	(revision 18470)
+++ smbd/dir.c	(working copy)
@@ -61,6 +61,7 @@
 	uint32 attr;
 	char *path;
 	BOOL has_wild; /* Set to true if the wcard entry has MS wildcard characters in it. */
+	BOOL did_stat; /* Optimisation for non-wcard searches. */
 };
 
 static struct bitmap *dptr_bmap;
@@ -535,6 +536,11 @@
 	return TellDir(dptr->dir_hnd);
 }
 
+BOOL dptr_has_wild(struct dptr_struct *dptr)
+{
+	return dptr->has_wild;
+}
+
 /****************************************************************************
  Return the next visible file name, skipping veto'd and invisible files.
 ****************************************************************************/
@@ -557,8 +563,6 @@
 
 const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
 {
-	pstring pathreal;
-
 	SET_STAT_INVALID(*pst);
 
 	if (dptr->has_wild) {
@@ -571,55 +575,62 @@
 		return NULL;
 	}
 
-	/* We know the stored wcard contains no wildcard characters. See if we can match
-	   with a stat call. If we can't, then set has_wild to true to
-	   prevent us from doing this on every call. */
+	if (!dptr->did_stat) {
+		pstring pathreal;
 
-	/* First check if it should be visible. */
-	if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
-		dptr->has_wild = True;
-		return dptr_normal_ReadDirName(dptr, poffset, pst);
-	}
+		/* We know the stored wcard contains no wildcard characters. See if we can match
+		   with a stat call. If we can't, then set did_stat to true to
+		   ensure we only do this once and keep searching. */
 
-	if (VALID_STAT(*pst)) {
-		/* We need to set the underlying dir_hdn offset to -1 also as
-		   this function is usually called with the output from TellDir. */
-		dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
-		return dptr->wcard;
-	}
+		dptr->did_stat = True;
 
-	pstrcpy(pathreal,dptr->path);
-	pstrcat(pathreal,"/");
-	pstrcat(pathreal,dptr->wcard);
+		/* First check if it should be visible. */
+		if (!is_visible_file(dptr->conn, dptr->path, dptr->wcard, pst, True)) {
+			/* This only returns False if the file was found, but
+			   is explicitly not visible. Set us to end of directory,
+			   but return NULL as we know we can't ever find it. */
+			dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
+			return NULL;
+		}
 
-	if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
-		/* We need to set the underlying dir_hdn offset to -1 also as
-		   this function is usually called with the output from TellDir. */
-		dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
-		return dptr->wcard;
-	} else {
-		/* If we get any other error than ENOENT or ENOTDIR
-		   then the file exists we just can't stat it. */
-		if (errno != ENOENT && errno != ENOTDIR) {
-			/* We need to set the underlying dir_hdn offset to -1 also as
+		if (VALID_STAT(*pst)) {
+			/* We need to set the underlying dir_hnd offset to -1 also as
 			   this function is usually called with the output from TellDir. */
 			dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
 			return dptr->wcard;
 		}
-	}
 
-	/* In case sensitive mode we don't search - we know if it doesn't exist 
-	   with a stat we will fail. */
+		pstrcpy(pathreal,dptr->path);
+		pstrcat(pathreal,"/");
+		pstrcat(pathreal,dptr->wcard);
 
-	if (dptr->conn->case_sensitive) {
-		/* We need to set the underlying dir_hdn offset to -1 also as
-		   this function is usually called with the output from TellDir. */
-		dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
-		return NULL;
-	} else {
-		dptr->has_wild = True;
-		return dptr_normal_ReadDirName(dptr, poffset, pst);
+		if (SMB_VFS_STAT(dptr->conn,pathreal,pst) == 0) {
+			/* We need to set the underlying dir_hnd offset to -1 also as
+			   this function is usually called with the output from TellDir. */
+			dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
+			return dptr->wcard;
+		} else {
+			/* If we get any other error than ENOENT or ENOTDIR
+			   then the file exists we just can't stat it. */
+			if (errno != ENOENT && errno != ENOTDIR) {
+				/* We need to set the underlying dir_hdn offset to -1 also as
+				   this function is usually called with the output from TellDir. */
+				dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
+				return dptr->wcard;
+			}
+		}
+
+		/* In case sensitive mode we don't search - we know if it doesn't exist 
+		   with a stat we will fail. */
+
+		if (dptr->conn->case_sensitive) {
+			/* We need to set the underlying dir_hnd offset to -1 also as
+			   this function is usually called with the output from TellDir. */
+			dptr->dir_hnd->offset = *poffset = END_OF_DIRECTORY_OFFSET;
+			return NULL;
+		}
 	}
+	return dptr_normal_ReadDirName(dptr, poffset, pst);
 }
 
 /****************************************************************************


More information about the samba-technical mailing list