KIP, Powerprint Request software -samba

James Peach jpeach at sgi.com
Sun Aug 15 23:59:43 GMT 2004


On Fri, Aug 13, 2004 at 10:19:20AM -0700, Jeremy Allison wrote:
> On Fri, Aug 13, 2004 at 11:43:10AM +0200, Martin Zielinski wrote:
> > 
> > That's not the problem. Even the directory listing from Windows, using the 
> > explorer is fast. 
> > I'm not so deep in Windows API, but the slow-down effect using the Powerprint 
> > application is caused by treating the request (samba calls it 
> > "trans2findfirst") as a request using a wildcard.
> > Maybe the correct behaviour to get the file info would be a different call 
> > from the Windows API - but I don't know.
> > 
> > Samba creates a directory listing for each file request with 
> > "dptr_create(...)" to find a match between the file and the directory 
> > content. 
> > 
> > I think, the way to fix this behaviour ist to detect, that the file name is 
> > NOT a wildcard but a valid file name. Checking, if we can get an excact match 
> > on the pattern, and - if so - skip the directory listing could be the trick. 
> > 
> > But I'm not deep enaugh in Samba to be really shure about that or even able to 
> > test it by hacking Samba :-(
> 
> Ah - great ! That's wonderful debugging. This is an optimisation I've
> been thinking of for a while. Can you get me the ethereal capture
> trace of this and a debug level 10 log ? It should be easy to fix
> this particular case !

It just so happens that some of our customers have been seeing this
problem with the findfirst code. I spent a chunk of last week putting
together the attached patch (against 3.0.6rc2) which
        1. Implements a lazy OpenDir for extremely large directory
        listings.
        2. Avoids walking the entire directory when there is an exact
        filename match.

It's a little complicated, but I _really_ wanted to avoid disturbing the
logic in get_lanman2_dir_entry().

-- 
James Peach | jpeach at sgi.com | SGI Australian Software Group
I don't speak for SGI.
-------------- next part --------------
diff -r -u reference/source/smbd/dir.c samba-3.0.5rc1/source/smbd/dir.c
--- reference/source/smbd/dir.c	Fri Jul  9 03:06:11 2004
+++ samba-3.0.5rc1/source/smbd/dir.c	Fri Aug  6 14:42:44 2004
@@ -19,11 +19,43 @@
 */
 
 #include "includes.h"
+#include <sys/pathname.h>
 
 /*
    This module implements directory related functions for Samba.
 */
 
+/* Directory abstraction. */
+typedef struct {
+	int pos;
+#define D_LAZY_READDIR  0x0001
+#define D_USE_VETO      0x0002
+#define D_CALLER_HIDES  0x0004
+        uint flags;
+        union {
+                /* A lazy directory hold the DIR* open and parcels entries out
+                 * using readdir/seekdir/etc. The caller may choose to do name
+                 * hiding itself by setting the D_CALLER_HIDES flag.
+                 */
+                struct {
+                        connection_struct *conn;
+                        DIR *dp;        /* open directory pointer */
+                        char *origpath; /* full path to directory */
+                } lazy;
+                /* A fixed directory reads the entries once at creation time,
+                 * hiding entries if necessary.
+                 */
+                struct {
+	                char *data;     /* buffer of saved names */
+	                char *current;  /* current name */
+	                int numentries;
+                } fixed;
+        } state;
+} Dir;
+
+#define IS_LAZY(d)      ((d)->flags & D_LAZY_READDIR)
+
+/* Per client directory state wrapper. */
 typedef struct _dptr_struct {
 	struct _dptr_struct *next, *prev;
 	int dnum;
@@ -30,12 +62,17 @@
 	uint16 spid;
 	connection_struct *conn;
 	void *ptr;
-	BOOL expect_close;
+#define D_EXPECT_CLOSE  0x0100
+	uint flags;
 	char *wcard; /* Field only used for trans2_ searches */
 	uint16 attr; /* Field only used for trans2_ searches */
 	char *path;
 } dptr_struct;
 
+#define EXPECT_CLOSE(d) ((d)->flags & D_EXPECT_CLOSE)
+
+static void *OpenSingletonDir(connection_struct *conn, const char *dname, const char * entry, BOOL use_veto);
+
 static struct bitmap *dptr_bmap;
 static dptr_struct *dirptrs;
 
@@ -121,8 +158,14 @@
 				if (dptrs_open >= MAX_OPEN_DIRECTORIES)
 					dptr_idleoldest();
 				DEBUG(4,("Reopening dptr key %d\n",key));
-				if ((dptr->ptr = OpenDir(dptr->conn, dptr->path, True)))
+				dptr->ptr =
+                                        IS_LAZY(dptr) ? OpenDirLazy(dptr->conn, dptr->path, True)
+                                                      : OpenDir(dptr->conn, dptr->path, True);
+
+				if (dptr->ptr) {
 					dptrs_open++;
+                                }
+
 			}
 			DLIST_PROMOTE(dirptrs,dptr);
 			return dptr;
@@ -179,11 +222,38 @@
 {
 	dptr_struct *dptr = dptr_get(key, False);
 
-	if (dptr) {
-		dptr->wcard = wcard;
-		return True;
-	}
-	return False;
+	if (!dptr)
+                return False;
+
+        dptr->wcard = wcard;
+
+        if (IS_LAZY(dptr) && dptr->ptr && !ms_has_wild(wcard)) {
+                void * newdir;
+
+                /* This wild card isn't really wild, so all we have to
+                 * worry about is case and suchlike. If we can create a
+                 * singleton Dir for this case, there must be an exact
+                 * match. If not, well no harm done .. we retain the
+                 * existing directory.
+                 */
+                if (newdir = OpenSingletonDir(dptr->conn, dptr->path, wcard, True)) {
+                        DEBUG(4,("replaced directory (path=%s) with singleton (entry=%s)\n",
+                                                dptr->path, wcard));
+
+                        /* If the connection_struct has a backpointer to the
+                         * directory iterator we just replaced, we'd better
+                         * update it.
+                         */
+                        if (dptr->conn->dirptr == dptr->ptr) {
+                                dptr->conn->dirptr = newdir;
+                        }
+
+                        CloseDir(dptr->ptr);
+                        dptr->ptr = newdir;
+                }
+        }
+
+        return True;
 }
 
 /****************************************************************************
@@ -327,7 +397,7 @@
  Start a directory listing.
 ****************************************************************************/
 
-static BOOL start_dir(connection_struct *conn, pstring directory)
+static BOOL start_dir(connection_struct *conn, pstring directory, BOOL lazy)
 {
 	const char *dir2;
 
@@ -342,7 +412,7 @@
 	if (! *dir2)
 		dir2 = ".";
 
-	conn->dirptr = OpenDir(conn, directory, True);
+	conn->dirptr = lazy ? OpenDirLazy(conn, directory, True) : OpenDir(conn, directory, True);
 	if (conn->dirptr) {    
 		dptrs_open++;
 		string_set(&conn->dirpath,directory);
@@ -380,7 +450,7 @@
 	 */
 
 	for(; dptr; dptr = dptr->prev) {
-		if ((old && (dptr->dnum < 256) && !dptr->expect_close) ||
+		if ((old && (dptr->dnum < 256) && !EXPECT_CLOSE(dptr)) ||
 			(!old && (dptr->dnum > 255))) {
 				dptr_close_internal(dptr);
 				return;
@@ -397,11 +467,11 @@
  me at Andrew's knee.... :-) :-). JRA.
 ****************************************************************************/
 
-int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid)
+static int dptr_create_common(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,BOOL lazy,uint16 spid)
 {
 	dptr_struct *dptr;
 
-	if (!start_dir(conn,path))
+	if (!start_dir(conn,path,lazy))
 		return(-2); /* Code to say use a unix error return code. */
 
 	if (dptrs_open >= MAX_OPEN_DIRECTORIES)
@@ -481,18 +551,33 @@
 	string_set(&dptr->path,path);
 	dptr->conn = conn;
 	dptr->spid = spid;
-	dptr->expect_close = expect_close;
+	dptr->flags = 0;
 	dptr->wcard = NULL; /* Only used in lanman2 searches */
 	dptr->attr = 0; /* Only used in lanman2 searches */
 
+        if (expect_close)
+	        dptr->flags |= D_EXPECT_CLOSE;
+        if (lazy)
+	        dptr->flags |= D_LAZY_READDIR;
+
 	DLIST_ADD(dirptrs, dptr);
 
 	DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
-		dptr->dnum,path,expect_close));  
+		dptr->dnum,path,EXPECT_CLOSE(dptr)));  
 
 	return(dptr->dnum);
 }
 
+int dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid)
+{
+        return dptr_create_common(conn, path, old_handle, expect_close, False /* lazy */, spid);
+}
+
+int dptr_create_lazy(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid)
+{
+        return dptr_create_common(conn, path, old_handle, expect_close, True /* lazy */, spid);
+}
+
 /****************************************************************************
  Fill the 5 byte server reserved dptr field.
 ****************************************************************************/
@@ -667,14 +752,6 @@
 	return(found);
 }
 
-typedef struct {
-	int pos;
-	int numentries;
-	int mallocsize;
-	char *data;
-	char *current;
-} Dir;
-
 /*******************************************************************
  Check to see if a user can read a file. This is only approximate,
  it is used as part of the "hide unreadable" option. Don't
@@ -807,9 +884,158 @@
 }
 
 /*******************************************************************
+  Should the given name be returned to the caller?
+********************************************************************/
+
+static BOOL user_can_see_file(connection_struct * conn,
+                const char * dirpath,
+                const char * fname,
+                BOOL         use_veto,
+                BOOL         must_stat)
+{
+        SMB_STRUCT_STAT st;
+        char *  entry = NULL;
+
+        if (conn == NULL)
+                return True;
+
+        /* If it's a vetoed file, pretend it doesn't even exist */
+        if (use_veto && IS_VETO_PATH(conn, fname))
+                return False;
+
+        ZERO_STRUCT(st);
+
+        /* In the case of a singleton directory, we have to stat to make sure
+         * the filename isn't bogus.
+         */
+        if (must_stat) {
+                int ret = 0;
+                if (entry || asprintf(&entry, "%s/%s", dirpath, fname) > 0) {
+                        ret = SMB_VFS_STAT(conn, entry, &st);
+                }
+                if (ret != 0) {
+                        SAFE_FREE(entry);
+                        return False;
+                }
+        }
+
+        /* Honour _hide unreadable_ option */
+        if (lp_hideunreadable(SNUM(conn))) {
+                int ret=0;
+
+                if (entry || asprintf(&entry, "%s/%s", dirpath, fname) > 0) {
+                        ret = user_can_read_file(conn, entry, &st);
+                }
+                if (!ret) {
+                        SAFE_FREE(entry);
+                        return False;
+                }
+        }
+
+        /* Honour _hide unwriteable_ option */
+        if (lp_hideunwriteable_files(SNUM(conn))) {
+                int ret=0;
+
+                if (entry || asprintf(&entry, "%s/%s", dirpath, fname) > 0) {
+                        ret = user_can_write_file(conn, entry, &st);
+                }
+                if (!ret) {
+                        SAFE_FREE(entry);
+                        return False;
+                }
+        }
+
+        /* Honour _hide_special_ option */
+        if (lp_hide_special_files(SNUM(conn))) {
+                int ret=0;
+
+                if (entry || asprintf(&entry, "%s/%s", dirpath, fname) > 0) {
+                        ret = file_is_special(conn, entry, &st);
+                }
+                if (ret) {
+                        SAFE_FREE(entry);
+                        return False;
+                }
+        }
+
+        SAFE_FREE(entry);
+        return True;
+}
+
+/*******************************************************************
  Open a directory.
 ********************************************************************/
 
+void *OpenDirLazy(connection_struct * conn, const char * name, BOOL use_veto)
+{
+	Dir *   dirp;
+	DIR *   dp;
+        char *  path = NULL;
+
+	if (!(dp = SMB_VFS_OPENDIR(conn, name)))
+		return(NULL);
+
+        asprintf(&path, "%s/%s", conn->origpath, name);
+	dirp = calloc(sizeof(Dir), 1);
+	if (!dirp || !path) {
+                SAFE_FREE(dirp);
+                SAFE_FREE(path);
+		DEBUG(0, ("Out of memory in OpenDirLazy\n"));
+		SMB_VFS_CLOSEDIR(conn,dp);
+		return(NULL);
+	}
+
+        dirp->flags = (D_LAZY_READDIR | D_CALLER_HIDES);
+        dirp->state.lazy.conn = conn;
+        dirp->state.lazy.origpath = path;
+        dirp->state.lazy.dp = dp;
+
+        if (use_veto)
+                dirp->flags |= D_USE_VETO;
+
+        return(dirp);
+}
+
+/* This function fakes up a fixed Dir structure. This is an optimisation for
+ * the case where a client does a FindFirst without a wildcard. In this case it
+ * might be possible to just hand out the requested file without reading all the
+ * directory entries. This is a big help when deleting large directories.
+ */
+static void *OpenSingletonDir(connection_struct *conn, const char *dirpath, const char *entry, BOOL use_veto)
+{
+        Dir *   dirp;
+        size_t  e_len; /* entry length */
+
+        if (!user_can_see_file(conn, dirpath, entry, use_veto, True /* must_stat */)) {
+                return(NULL);
+        }
+
+	dirp = (Dir *)calloc(sizeof(Dir), 1);
+	if (!dirp) {
+		DEBUG(0,("Out of memory in OpenSingletonDir\n"));
+		return(NULL);
+	}
+
+        e_len = strlen(entry);
+#define S_DOTDOT_SZ (sizeof(".\0.."))
+
+        dirp->state.fixed.data = malloc(S_DOTDOT_SZ + e_len + 1);
+        if (!dirp->state.fixed.data) {
+                SAFE_FREE(dirp);
+		DEBUG(0,("Out of memory in OpenSingletonDir\n"));
+		return(NULL);
+        }
+
+        memcpy(dirp->state.fixed.data, ".\0..", S_DOTDOT_SZ);
+        memcpy(dirp->state.fixed.data + S_DOTDOT_SZ, entry, e_len + 1);
+
+        dirp->state.fixed.numentries = 3;
+        dirp->state.fixed.current = dirp->state.fixed.data;
+        return(dirp);
+
+#undef S_DOTDOT_SZ
+}
+
 void *OpenDir(connection_struct *conn, const char *name, BOOL use_veto)
 {
 	Dir *dirp;
@@ -816,23 +1042,29 @@
 	const char *n;
 	DIR *p = SMB_VFS_OPENDIR(conn,name);
 	int used=0;
+        char *dirpath=NULL;
+        size_t mallocsize = 0;
 
 	if (!p)
 		return(NULL);
-	dirp = (Dir *)malloc(sizeof(Dir));
-	if (!dirp) {
+
+	dirp = (Dir *)calloc(sizeof(Dir), 1);
+        asprintf(&dirpath, "%s/%s", conn->origpath, name);
+
+	if (!dirp || !dirpath) {
+                SAFE_FREE(dirp);
+                SAFE_FREE(dirpath);
 		DEBUG(0,("Out of memory in OpenDir\n"));
 		SMB_VFS_CLOSEDIR(conn,p);
 		return(NULL);
 	}
-	dirp->pos = dirp->numentries = dirp->mallocsize = 0;
-	dirp->data = dirp->current = NULL;
 
+        if (use_veto)
+                dirp->flags |= D_USE_VETO;
+
 	while (True) {
 		int l;
 		BOOL normal_entry = True;
-		SMB_STRUCT_STAT st;
-		char *entry = NULL;
 
 		if (used == 0) {
 			n = ".";
@@ -849,72 +1081,31 @@
 			normal_entry = True;
 	    	}
 
-		ZERO_STRUCT(st);
-		l = strlen(n)+1;
-
-		/* If it's a vetoed file, pretend it doesn't even exist */
-		if (normal_entry && use_veto && conn && IS_VETO_PATH(conn, n))
-			continue;
-
-		/* Honour _hide unreadable_ option */
-		if (normal_entry && conn && lp_hideunreadable(SNUM(conn))) {
-			int ret=0;
-      
-			if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
-				ret = user_can_read_file(conn, entry, &st);
-			}
-			if (!ret) {
-				SAFE_FREE(entry);
-				continue;
-			}
-		}
-
-		/* Honour _hide unwriteable_ option */
-		if (normal_entry && conn && lp_hideunwriteable_files(SNUM(conn))) {
-			int ret=0;
-      
-			if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
-				ret = user_can_write_file(conn, entry, &st);
-			}
-			if (!ret) {
-				SAFE_FREE(entry);
-				continue;
-			}
-		}
-
-		/* Honour _hide_special_ option */
-		if (normal_entry && conn && lp_hide_special_files(SNUM(conn))) {
-			int ret=0;
-      
-			if (entry || asprintf(&entry, "%s/%s/%s", conn->origpath, name, n) > 0) {
-				ret = file_is_special(conn, entry, &st);
-			}
-			if (ret) {
-				SAFE_FREE(entry);
-				continue;
-			}
-		}
-
-		SAFE_FREE(entry);
+                if (normal_entry && !user_can_see_file(conn, dirpath, n,
+                                        dirp->flags & D_USE_VETO, False /* must_stat */)) {
+                        continue;
+                }
 
-		if (used + l > dirp->mallocsize) {
+		l = strlen(n)+1;
+		if (used + l > mallocsize) {
 			int s = MAX(used+l,used+2000);
 			char *r;
-			r = (char *)Realloc(dirp->data,s);
+			r = (char *)Realloc(dirp->state.fixed.data,s);
 			if (!r) {
 				DEBUG(0,("Out of memory in OpenDir\n"));
 					break;
 			}
-			dirp->data = r;
-			dirp->mallocsize = s;
-			dirp->current = dirp->data;
+			dirp->state.fixed.data = r;
+			mallocsize = s;
+			dirp->state.fixed.current = dirp->state.fixed.data;
 		}
 
-		safe_strcpy_base(dirp->data+used,n, dirp->data, dirp->mallocsize);
+		safe_strcpy_base(dirp->state.fixed.data+used,n, dirp->state.fixed.data, mallocsize);
 		used += l;
-		dirp->numentries++;
+		dirp->state.fixed.numentries++;
 	}
 
+        SAFE_FREE(dirpath);
 	SMB_VFS_CLOSEDIR(conn,p);
 	return((void *)dirp);
 }
@@ -926,9 +1117,17 @@
 
 void CloseDir(void *p)
 {
+	Dir *dirp = (Dir *)p;
 	if (!p)
 		return;    
-	SAFE_FREE(((Dir *)p)->data);
+
+        if (IS_LAZY(dirp)) {
+	        SMB_VFS_CLOSEDIR(dirp->state.lazy.conn, dirp->state.lazy.dp);
+	        SAFE_FREE(dirp->state.lazy.origpath);
+        } else {
+	        SAFE_FREE(dirp->state.fixed.data);
+        }
+
 	SAFE_FREE(p);
 }
 
@@ -941,16 +1140,50 @@
 	char *ret;
 	Dir *dirp = (Dir *)p;
 
-	if (!dirp || !dirp->current || dirp->pos >= dirp->numentries)
-		return(NULL);
+        if (!dirp || !dirp->state.fixed.current)
+                return(NULL);
 
-	ret = dirp->current;
-	dirp->current = skip_string(dirp->current,1);
-	dirp->pos++;
+        if (IS_LAZY(dirp)) {
+                while (ret = vfs_readdirname(dirp->state.lazy.conn, dirp->state.lazy.dp)) {
+                        dirp->pos++;
+
+                        /* Skip checks for . and .. or if caller is doing them. */
+                        if ((dirp->flags & D_CALLER_HIDES) || ISDOT(ret) || ISDOTDOT(ret)) {
+                                break;
+                        }
+
+                        if (user_can_see_file(dirp->state.lazy.conn, dirp->state.lazy.origpath,
+                                                ret, dirp->flags & D_USE_VETO, False /* must_stat */)) {
+                                break;
+                        }
+                }
+                /* Don't update pos because telldir does an lseek, which is a
+                 * syscall we just don't need.
+                 */
+        } else {
+                if (dirp->pos >= dirp->state.fixed.numentries)
+                        return(NULL);
+
+                ret = dirp->state.fixed.current;
+                dirp->state.fixed.current = skip_string(dirp->state.fixed.current,1);
+                dirp->pos++;
+        }
 
 	return(ret);
 }
 
+BOOL HideDirEntry(void * p, const char * name)
+{
+	Dir *dirp = (Dir *)p;
+
+        if (dirp->flags & D_CALLER_HIDES) {
+                return !user_can_see_file(dirp->state.lazy.conn, dirp->state.lazy.origpath,
+                                                name, dirp->flags & D_USE_VETO, False /* must_stat */);
+        } else {
+                return False;
+        }
+}
+
 /*******************************************************************
  Seek a dir.
 ********************************************************************/
@@ -959,16 +1192,21 @@
 {
 	Dir *dirp = (Dir *)p;
 
-	if (!dirp)
+	if (!dirp || pos < 0)
 		return(False);
 
-	if (pos < dirp->pos) {
-		dirp->current = dirp->data;
-		dirp->pos = 0;
-	}
+        if (pos < dirp->pos) {
+                if (IS_LAZY(dirp)) {
+                        rewinddir(dirp->state.lazy.dp);
+                        dirp->pos = 0;
+                } else {
+                        dirp->state.fixed.current = dirp->state.fixed.data;
+                        dirp->pos = 0;
+                }
+        }
 
-	while (dirp->pos < pos && ReadDirName(p))
-		;
+        while (dirp->pos < pos && ReadDirName(p))
+                ;
 
 	return (dirp->pos == pos);
 }
diff -r -u reference/source/smbd/notify_hash.c samba-3.0.5rc1/source/smbd/notify_hash.c
--- reference/source/smbd/notify_hash.c	Thu Aug  5 15:25:54 2004
+++ samba-3.0.5rc1/source/smbd/notify_hash.c	Tue Aug  3 16:34:16 2004
@@ -90,7 +90,7 @@
 	 * larger than the max time_t value).
 	 */
 
-	dp = OpenDir(conn, path, True);
+	dp = OpenDirLazy(conn, path, True);
 	if (dp == NULL)
 		return False;
 
diff -r -u reference/source/smbd/reply.c samba-3.0.5rc1/source/smbd/reply.c
--- reference/source/smbd/reply.c	Fri Jul  9 03:06:10 2004
+++ samba-3.0.5rc1/source/smbd/reply.c	Thu Aug  5 15:35:49 2004
@@ -1600,7 +1600,7 @@
 		const char *dname;
 		
 		if (check_name(directory,conn))
-			dirptr = OpenDir(conn, directory, True);
+			dirptr = OpenDirLazy(conn, directory, True);
 		
 		/* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
 		   the pattern matches against the long name, otherwise the short name 
@@ -1631,7 +1631,10 @@
 
 				if(!mask_match(fname, mask, conn->case_sensitive))
 					continue;
-				
+
+                                if (HideDirEntry(dirptr, dname))
+                                        continue;
+
 				if (sys_direntry) {
 					error = NT_STATUS_OBJECT_NAME_INVALID;
 					DEBUG(3,("unlink_internals: system directory delete denied [%s] mask [%s]\n",
@@ -3887,7 +3890,7 @@
 		pstring destname;
 		
 		if (check_name(directory,conn))
-			dirptr = OpenDir(conn, directory, True);
+			dirptr = OpenDirLazy(conn, directory, True);
 		
 		if (dirptr) {
 			error = NT_STATUS_NO_SUCH_FILE;
@@ -3915,7 +3918,10 @@
 
 				if(!mask_match(fname, mask, conn->case_sensitive))
 					continue;
-				
+
+                                if (HideDirEntry(dirptr, dname))
+                                        continue;
+
 				if (sysdir_entry) {
 					error = NT_STATUS_OBJECT_NAME_INVALID;
 					break;
@@ -4240,7 +4246,7 @@
 		pstring destname;
 
 		if (check_name(directory,conn))
-			dirptr = OpenDir(conn, directory, True);
+			dirptr = OpenDirLazy(conn, directory, True);
 
 		if (dirptr) {
 			error = ERRbadfile;
@@ -4254,6 +4260,9 @@
     
 				if(!mask_match(fname, mask, conn->case_sensitive))
 					continue;
+
+                                if (HideDirEntry(dirptr, dname))
+                                        continue;
 
 				error = ERRnoaccess;
 				slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
diff -r -u reference/source/smbd/trans2.c samba-3.0.5rc1/source/smbd/trans2.c
--- reference/source/smbd/trans2.c	Fri Jul  9 03:06:11 2004
+++ samba-3.0.5rc1/source/smbd/trans2.c	Fri Aug  6 14:47:53 2004
@@ -882,8 +882,8 @@
 
 		reskey = 0;
 
-		DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
-			(long)conn->dirptr,TellDir(conn->dirptr)));
+		DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset=%d entry=\n",
+			(long)conn->dirptr,TellDir(conn->dirptr), dname));
       
 		if (!dname) 
 			return(False);
@@ -893,6 +893,13 @@
 		if(!(got_match = *got_exact_match = exact_match(fname, mask, conn->case_sensitive)))
 			got_match = mask_match(fname, mask, conn->case_sensitive);
 
+                /* If we have a lazy directory iterator, we might need to
+                 * exclude (potentially matching) this entry.
+                 */
+                if (got_match && HideDirEntry(conn->dirptr, dname)) {
+                        got_match = False;
+                }
+
 		if(!got_match && !mangle_is_8_3(fname, False)) {
 
 			/*
@@ -1422,7 +1429,8 @@
 		return ERROR_DOS(ERRDOS,ERRnomem);
 	*pparams = params;
 
-	dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
+        dptr_num = dptr_create_lazy(conn,directory, False, True, SVAL(inbuf,smb_pid));
+
 	if (dptr_num < 0)
 		return(UNIXERROR(ERRDOS,ERRbadfile));
 
@@ -1707,7 +1715,7 @@
 		if(current_pos < 0) {
 			DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos));
 			SeekDir(dirptr, start_pos);
-			for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) {
+			for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; ++current_pos) {
 
 				/*
 				 * Remember, mangle_map is called by


More information about the samba-technical mailing list