[patch]: optimization for findfirst when in case-sensitive mode

Matt Mitchell mmitchell at virtualproperties.com
Sun Dec 12 22:59:16 GMT 2004


Jeremy Allison wrote:
> On Fri, Dec 10, 2004 at 05:41:08PM -0600, Matt Mitchell wrote:
> 
>>Jeremy (and all),
>>
>>Here is a first crack at a patch implementing an optimization where, 
>>given that
>>
>>Any comments or slams appreciated.  Yes, it is a hack.
> 
> 
> No patch attached I'm afraid.... :-).

That's what I get for trying to wrap things up right before the holiday 
party.  :)

Here are the patches.  For real this time.

-m
-------------- next part --------------
--- samba3-orig/source/smbd/trans2.c	2004-12-10 17:26:44.000000000 -0600
+++ samba3/source/smbd/trans2.c	2004-12-10 17:11:19.000000000 -0600
@@ -33,6 +33,12 @@
 #define get_file_size(sbuf) ((sbuf).st_size)
 #define DIR_ENTRY_SAFETY_MARGIN 4096
 
+static BOOL populate_lanman2_dir_entry(connection_struct *conn, 
+				void *outbuf, char** ppdata, char** pp,
+				pstring fname, pstring pathreal,
+				int dirtype, int info_level,
+				int requires_resume_key,
+				SMB_STRUCT_STAT sbuf, char* base_data, int* last_name_off);
 /********************************************************************
  Roundup a value to the nearest SMB_ROUNDUP_ALLOCATION_SIZE boundary.
  Only do this for Windows clients.
@@ -835,17 +841,11 @@
 	pstring mask;
 	pstring pathreal;
 	pstring fname;
-	char *p, *q, *pdata = *ppdata;
+	char *p, *pdata = *ppdata;
 	uint32 reskey=0;
 	int prev_dirpos=0;
 	int mode=0;
-	SMB_OFF_T file_size = 0;
-	SMB_BIG_UINT allocation_size = 0;
-	uint32 len;
-	time_t mdate=0, adate=0, cdate=0;
 	char *nameptr;
-	BOOL was_8_3;
-	int nt_extmode; /* Used for NT connections instead of mode */
 	BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
 
 	*fname = 0;
@@ -944,35 +944,14 @@
 				}
 			}
 
-			mode = dos_mode(conn,pathreal,&sbuf);
+			DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
 
+			mode = dos_mode(conn,pathreal,&sbuf);
+	  
 			if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
 				DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
-				continue;
-			}
-
-			file_size = get_file_size(sbuf);
-			allocation_size = get_allocation_size(NULL,&sbuf);
-			mdate = sbuf.st_mtime;
-			adate = sbuf.st_atime;
-			cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
-
-			if (lp_dos_filetime_resolution(SNUM(conn))) {
-				cdate &= ~1;
-				mdate &= ~1;
-				adate &= ~1;
-			}
-
-			if(mode & aDIR) {
-				/* This is necessary, as otherwise the
-				 * desktop.ini file in this folder is
-				 * ignored */
-				mode |= (lp_profile_acls(SNUM(conn)) ? aRONLY : 0);
-				file_size = 0;
+				return False;
 			}
-
-			DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
-	  
 			found = True;
 		}
 	}
@@ -982,411 +961,103 @@
 	p = pdata;
 	nameptr = p;
 
-	nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
+	if(!populate_lanman2_dir_entry(conn, 
+			outbuf, ppdata, &p, 
+			fname, pathreal,
+			dirtype, info_level,
+			requires_resume_key, 
+			sbuf, base_data, last_name_off)) {
+		/* Some problem we should probably do a better job of handling... */
+		DEBUG(3,("populate_lanman2_dir_entry failed!"));
+		return False;
+	}
+			
+	
+	if (PTR_DIFF(p,pdata) > space_remaining) {
+		/* Move the dirptr back to prev_dirpos */
+		SeekDir(conn->dirptr, prev_dirpos);
+		*out_of_space = True;
+		DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
+		return False; /* Not finished - just out of space */
+	}
 
-	switch (info_level) {
-		case SMB_INFO_STANDARD:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_STANDARD\n"));
-			if(requires_resume_key) {
-				SIVAL(p,0,reskey);
-				p += 4;
-			}
-			put_dos_date2(p,l1_fdateCreation,cdate);
-			put_dos_date2(p,l1_fdateLastAccess,adate);
-			put_dos_date2(p,l1_fdateLastWrite,mdate);
-			SIVAL(p,l1_cbFile,(uint32)file_size);
-			SIVAL(p,l1_cbFileAlloc,(uint32)allocation_size);
-			SSVAL(p,l1_attrFile,mode);
-			p += l1_achName;
-			nameptr = p;
-			p += align_string(outbuf, p, 0);
-			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
-			if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
-				if (len > 2) {
-					SCVAL(nameptr, -1, len - 2);
-				} else {
-					SCVAL(nameptr, -1, 0);
-				}
-			} else {
-				if (len > 1) {
-					SCVAL(nameptr, -1, len - 1);
-				} else {
-					SCVAL(nameptr, -1, 0);
-				}
-			}
-			p += len;
-			break;
+	/* Setup the last_filename pointer, as an offset from base_data */
+	/* *last_name_off = PTR_DIFF(nameptr,base_data); */
+	/* Advance the data pointer to the next slot */
+	*ppdata = p;
 
-		case SMB_INFO_QUERY_EA_SIZE:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_QUERY_EA_SIZE\n"));
-			if(requires_resume_key) {
-				SIVAL(p,0,reskey);
-				p += 4;
-			}
-			put_dos_date2(p,l2_fdateCreation,cdate);
-			put_dos_date2(p,l2_fdateLastAccess,adate);
-			put_dos_date2(p,l2_fdateLastWrite,mdate);
-			SIVAL(p,l2_cbFile,(uint32)file_size);
-			SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size);
-			SSVAL(p,l2_attrFile,mode);
-			{
-				unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
-				SIVAL(p,l2_cbList,ea_size); /* Extended attributes */
-			}
-			p += l2_achName;
-			nameptr = p - 1;
-			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE | STR_NOALIGN);
-			if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
-				if (len > 2) {
-					len -= 2;
-				} else {
-					len = 0;
-				}
-			} else {
-				if (len > 1) {
-					len -= 1;
-				} else {
-					len = 0;
-				}
-			}
-			SCVAL(nameptr,0,len);
-			p += len;
-			SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
-			break;
+	return(found);
+}
 
-		case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
-			was_8_3 = mangle_is_8_3(fname, True);
-			p += 4;
-			SIVAL(p,0,reskey); p += 4;
-			put_long_date(p,cdate); p += 8;
-			put_long_date(p,adate); p += 8;
-			put_long_date(p,mdate); p += 8;
-			put_long_date(p,mdate); p += 8;
-			SOFF_T(p,0,file_size); p += 8;
-			SOFF_T(p,0,allocation_size); p += 8;
-			SIVAL(p,0,nt_extmode); p += 4;
-			q = p; p += 4; /* q is placeholder for name length. */
-			{
-				unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
-				SIVAL(p,0,ea_size); /* Extended attributes */
-				p += 4;
-			}
-			/* Clear the short name buffer. This is
-			 * IMPORTANT as not doing so will trigger
-			 * a Win2k client bug. JRA.
-			 */
-			memset(p,'\0',26);
-			if (!was_8_3 && lp_manglednames(SNUM(conn))) {
-				pstring mangled_name;
-				pstrcpy(mangled_name, fname);
-				mangle_map(mangled_name,True,True,SNUM(conn));
-				mangled_name[12] = 0;
-				len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
-				SSVAL(p, 0, len);
-			} else {
-				SSVAL(p,0,0);
-				*(p+2) = 0;
-			}
-			p += 2 + 24;
-			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
-			SIVAL(q,0,len);
-			p += len;
-			len = PTR_DIFF(p, pdata);
-			len = (len + 3) & ~3;
-			SIVAL(pdata,0,len);
-			p = pdata + len;
-			break;
+/****************************************************************************
+ Reply to a TRANS2_FINDFIRST.
+****************************************************************************/
 
-		case SMB_FIND_FILE_DIRECTORY_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
-			p += 4;
-			SIVAL(p,0,reskey); p += 4;
-			put_long_date(p,cdate); p += 8;
-			put_long_date(p,adate); p += 8;
-			put_long_date(p,mdate); p += 8;
-			put_long_date(p,mdate); p += 8;
-			SOFF_T(p,0,file_size); p += 8;
-			SOFF_T(p,0,allocation_size); p += 8;
-			SIVAL(p,0,nt_extmode); p += 4;
-			len = srvstr_push(outbuf, p + 4, fname, -1, STR_TERMINATE_ASCII);
-			SIVAL(p,0,len);
-			p += 4 + len;
-			len = PTR_DIFF(p, pdata);
-			len = (len + 3) & ~3;
-			SIVAL(pdata,0,len);
-			p = pdata + len;
-			break;
-      
-		case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
-			p += 4;
-			SIVAL(p,0,reskey); p += 4;
-			put_long_date(p,cdate); p += 8;
-			put_long_date(p,adate); p += 8;
-			put_long_date(p,mdate); p += 8;
-			put_long_date(p,mdate); p += 8;
-			SOFF_T(p,0,file_size); p += 8;
-			SOFF_T(p,0,allocation_size); p += 8;
-			SIVAL(p,0,nt_extmode); p += 4;
-			q = p; p += 4; /* q is placeholder for name length. */
-			{
-				unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
-				SIVAL(p,0,ea_size); /* Extended attributes */
-				p +=4;
-			}
-			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
-			SIVAL(q, 0, len);
-			p += len;
+static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,  
+				char **pparams, int total_params, char **ppdata, int total_data,
+				unsigned int max_data_bytes)
+{
+	/* We must be careful here that we don't return more than the
+		allowed number of data bytes. If this means returning fewer than
+		maxentries then so be it. We assume that the redirector has
+		enough room for the fixed number of parameter bytes it has
+		requested. */
+	char *params = *pparams;
+	char *pdata = *ppdata;
+	int dirtype = SVAL(params,0);
+	int maxentries = SVAL(params,2);
+	uint16 findfirst_flags = SVAL(params,4);
+	BOOL close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
+	BOOL close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
+	BOOL requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
+	int info_level = SVAL(params,6);
+	pstring directory;
+	pstring mask;
+	char *p, *wcard;
+	int last_name_off=0;
+	int dptr_num = -1;
+	int numentries = 0;
+	int i;
+	BOOL finished = False;
+	BOOL dont_descend = False;
+	BOOL out_of_space = False;
+	int space_remaining;
+	BOOL bad_path = False;
+	SMB_STRUCT_STAT sbuf;
+	NTSTATUS ntstatus = NT_STATUS_OK;
 
-			len = PTR_DIFF(p, pdata);
-			len = (len + 3) & ~3;
-			SIVAL(pdata,0,len);
-			p = pdata + len;
-			break;
+	if (total_params < 12)
+		return(ERROR_DOS(ERRDOS,ERRinvalidparam));
+
+	*directory = *mask = 0;
+
+	DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, \
+close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
+		dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
+		info_level, max_data_bytes));
 
+	if (!maxentries) {
+		/* W2K3 seems to treat zero as 1. */
+		maxentries = 1;
+	}
+ 
+	switch (info_level) {
+		case SMB_INFO_STANDARD:
+		case SMB_INFO_QUERY_EA_SIZE:
+		case SMB_FIND_FILE_DIRECTORY_INFO:
+		case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
 		case SMB_FIND_FILE_NAMES_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
-			p += 4;
-			SIVAL(p,0,reskey); p += 4;
-			p += 4;
-			/* this must *not* be null terminated or w2k gets in a loop trying to set an
-			   acl on a dir (tridge) */
-			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
-			SIVAL(p, -4, len);
-			p += len;
-			len = PTR_DIFF(p, pdata);
-			len = (len + 3) & ~3;
-			SIVAL(pdata,0,len);
-			p = pdata + len;
+		case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+		case SMB_FIND_ID_FULL_DIRECTORY_INFO:
+		case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
+			break;
+		case SMB_FIND_FILE_UNIX:
+			if (!lp_unix_extensions())
+				return(ERROR_DOS(ERRDOS,ERRunknownlevel));
 			break;
-
-		case SMB_FIND_ID_FULL_DIRECTORY_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
-			p += 4;
-			SIVAL(p,0,reskey); p += 4;
-			put_long_date(p,cdate); p += 8;
-			put_long_date(p,adate); p += 8;
-			put_long_date(p,mdate); p += 8;
-			put_long_date(p,mdate); p += 8;
-			SOFF_T(p,0,file_size); p += 8;
-			SOFF_T(p,0,allocation_size); p += 8;
-			SIVAL(p,0,nt_extmode); p += 4;
-			q = p; p += 4; /* q is placeholder for name length. */
-			{
-				unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
-				SIVAL(p,0,ea_size); /* Extended attributes */
-				p +=4;
-			}
-			SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
-			SIVAL(p,0,sbuf.st_dev); p += 4;
-			SIVAL(p,0,sbuf.st_ino); p += 4;
-			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
-			SIVAL(q, 0, len);
-			p += len; 
-			len = PTR_DIFF(p, pdata);
-			len = (len + 3) & ~3;
-			SIVAL(pdata,0,len);
-			p = pdata + len;
-			break;
-
-		case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
-			was_8_3 = mangle_is_8_3(fname, True);
-			p += 4;
-			SIVAL(p,0,reskey); p += 4;
-			put_long_date(p,cdate); p += 8;
-			put_long_date(p,adate); p += 8;
-			put_long_date(p,mdate); p += 8;
-			put_long_date(p,mdate); p += 8;
-			SOFF_T(p,0,file_size); p += 8;
-			SOFF_T(p,0,allocation_size); p += 8;
-			SIVAL(p,0,nt_extmode); p += 4;
-			q = p; p += 4; /* q is placeholder for name length */
-			{
-				unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
-				SIVAL(p,0,ea_size); /* Extended attributes */
-				p +=4;
-			}
-			/* Clear the short name buffer. This is
-			 * IMPORTANT as not doing so will trigger
-			 * a Win2k client bug. JRA.
-			 */
-			memset(p,'\0',26);
-			if (!was_8_3 && lp_manglednames(SNUM(conn))) {
-				pstring mangled_name;
-				pstrcpy(mangled_name, fname);
-				mangle_map(mangled_name,True,True,SNUM(conn));
-				mangled_name[12] = 0;
-				len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
-				SSVAL(p, 0, len);
-			} else {
-				SSVAL(p,0,0);
-				*(p+2) = 0;
-			}
-			p += 26;
-			SSVAL(p,0,0); p += 2; /* Reserved ? */
-			SIVAL(p,0,sbuf.st_dev); p += 4;
-			SIVAL(p,0,sbuf.st_ino); p += 4;
-			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
-			SIVAL(q,0,len);
-			p += len;
-			len = PTR_DIFF(p, pdata);
-			len = (len + 3) & ~3;
-			SIVAL(pdata,0,len);
-			p = pdata + len;
-			break;
-
-		/* CIFS UNIX Extension. */
-
-		case SMB_FIND_FILE_UNIX:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
-			p+= 4;
-			SIVAL(p,0,reskey); p+= 4;    /* Used for continuing search. */
-
-			/* Begin of SMB_QUERY_FILE_UNIX_BASIC */
-			SOFF_T(p,0,get_file_size(sbuf));             /* File size 64 Bit */
-			p+= 8;
-
-			SOFF_T(p,0,get_allocation_size(NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */
-			p+= 8;
-
-			put_long_date(p,sbuf.st_ctime);       /* Inode change Time 64 Bit */
-			put_long_date(p+8,sbuf.st_atime);     /* Last access time 64 Bit */
-			put_long_date(p+16,sbuf.st_mtime);    /* Last modification time 64 Bit */
-			p+= 24;
-
-			SIVAL(p,0,sbuf.st_uid);               /* user id for the owner */
-			SIVAL(p,4,0);
-			p+= 8;
-
-			SIVAL(p,0,sbuf.st_gid);               /* group id of owner */
-			SIVAL(p,4,0);
-			p+= 8;
-
-			SIVAL(p,0,unix_filetype(sbuf.st_mode));
-			p+= 4;
-
-			SIVAL(p,0,unix_dev_major(sbuf.st_rdev));   /* Major device number if type is device */
-			SIVAL(p,4,0);
-			p+= 8;
-
-			SIVAL(p,0,unix_dev_minor(sbuf.st_rdev));   /* Minor device number if type is device */
-			SIVAL(p,4,0);
-			p+= 8;
-
-			SINO_T(p,0,(SMB_INO_T)sbuf.st_ino);   /* inode number */
-			p+= 8;
-
-			SIVAL(p,0, unix_perms_to_wire(sbuf.st_mode));     /* Standard UNIX file permissions */
-			SIVAL(p,4,0);
-			p+= 8;
-
-			SIVAL(p,0,sbuf.st_nlink);             /* number of hard links */
-			SIVAL(p,4,0);
-			p+= 8;
-
-			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
-			p += len;
-
-			len = PTR_DIFF(p, pdata);
-			len = (len + 3) & ~3;
-			SIVAL(pdata,0,len);	/* Offset from this structure to the beginning of the next one */
-			p = pdata + len;
-			/* End of SMB_QUERY_FILE_UNIX_BASIC */
-
-			break;
-
-		default:      
-			return(False);
-	}
-
-
-	if (PTR_DIFF(p,pdata) > space_remaining) {
-		/* Move the dirptr back to prev_dirpos */
-		SeekDir(conn->dirptr, prev_dirpos);
-		*out_of_space = True;
-		DEBUG(9,("get_lanman2_dir_entry: out of space\n"));
-		return False; /* Not finished - just out of space */
-	}
-
-	/* Setup the last_filename pointer, as an offset from base_data */
-	*last_name_off = PTR_DIFF(nameptr,base_data);
-	/* Advance the data pointer to the next slot */
-	*ppdata = p;
-
-	return(found);
-}
-
-/****************************************************************************
- Reply to a TRANS2_FINDFIRST.
-****************************************************************************/
-
-static int call_trans2findfirst(connection_struct *conn, char *inbuf, char *outbuf, int bufsize,  
-				char **pparams, int total_params, char **ppdata, int total_data,
-				unsigned int max_data_bytes)
-{
-	/* We must be careful here that we don't return more than the
-		allowed number of data bytes. If this means returning fewer than
-		maxentries then so be it. We assume that the redirector has
-		enough room for the fixed number of parameter bytes it has
-		requested. */
-	char *params = *pparams;
-	char *pdata = *ppdata;
-	int dirtype = SVAL(params,0);
-	int maxentries = SVAL(params,2);
-	uint16 findfirst_flags = SVAL(params,4);
-	BOOL close_after_first = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE);
-	BOOL close_if_end = (findfirst_flags & FLAG_TRANS2_FIND_CLOSE_IF_END);
-	BOOL requires_resume_key = (findfirst_flags & FLAG_TRANS2_FIND_REQUIRE_RESUME);
-	int info_level = SVAL(params,6);
-	pstring directory;
-	pstring mask;
-	char *p, *wcard;
-	int last_name_off=0;
-	int dptr_num = -1;
-	int numentries = 0;
-	int i;
-	BOOL finished = False;
-	BOOL dont_descend = False;
-	BOOL out_of_space = False;
-	int space_remaining;
-	BOOL bad_path = False;
-	SMB_STRUCT_STAT sbuf;
-	NTSTATUS ntstatus = NT_STATUS_OK;
-
-	if (total_params < 12)
-		return(ERROR_DOS(ERRDOS,ERRinvalidparam));
-
-	*directory = *mask = 0;
-
-	DEBUG(3,("call_trans2findfirst: dirtype = %d, maxentries = %d, close_after_first=%d, \
-close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n",
-		dirtype, maxentries, close_after_first, close_if_end, requires_resume_key,
-		info_level, max_data_bytes));
-
-	if (!maxentries) {
-		/* W2K3 seems to treat zero as 1. */
-		maxentries = 1;
-	}
- 
-	switch (info_level) {
-		case SMB_INFO_STANDARD:
-		case SMB_INFO_QUERY_EA_SIZE:
-		case SMB_FIND_FILE_DIRECTORY_INFO:
-		case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
-		case SMB_FIND_FILE_NAMES_INFO:
-		case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
-		case SMB_FIND_ID_FULL_DIRECTORY_INFO:
-		case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
-			break;
-		case SMB_FIND_FILE_UNIX:
-			if (!lp_unix_extensions())
-				return(ERROR_DOS(ERRDOS,ERRunknownlevel));
-			break;
-		default:
-			return(ERROR_DOS(ERRDOS,ERRunknownlevel));
-	}
+		default:
+			return(ERROR_DOS(ERRDOS,ERRunknownlevel));
+	}
 
 	srvstr_get_path(inbuf, directory, params+12, sizeof(directory), -1, STR_TERMINATE, &ntstatus, True);
 	if (!NT_STATUS_IS_OK(ntstatus)) {
@@ -4574,3 +4245,384 @@
 	END_PROFILE(SMBtrans2);
 	return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
 }
+
+/**************************************************************************
+ * Actually populate the lanman buffer pointed to by *ppdata.  Split out
+ * of get_lanman2_dir_entry so that we could short-circuit the dirptr
+ * operations where possible.
+ **************************************************************************/
+static BOOL populate_lanman2_dir_entry(connection_struct *conn, 
+				void *outbuf, char** ppdata, char** pp,
+				pstring fname, pstring pathreal,
+				int dirtype, int info_level,
+				int requires_resume_key,
+				SMB_STRUCT_STAT sbuf, char* base_data, int* last_name_off)
+{
+	BOOL was_8_3 = False;
+	SMB_OFF_T file_size;
+	SMB_BIG_UINT allocation_size;
+	int len = 0;
+	char *pdata = *ppdata;
+	char *p = *pp;
+	char *nameptr = p;
+	char *q;
+	int mode;
+	int cdate, mdate, adate;
+	int nt_extmode; /* Used for NT connections instead of mode */
+	uint32 reskey = 0;
+
+	DEBUG(10,("conn 0x%p, outbuf 0x%p, ppdata 0x%p, pp 0x%p, fname %s, pathreal %s, dirtype %d, info_level %d, requires_resume_key %d, base_data 0x%p\n",
+				conn, outbuf, ppdata, pp, fname, pathreal, dirtype, info_level, requires_resume_key, base_data));
+
+	mode = dos_mode(conn,pathreal,&sbuf);
+	DEBUG(5,("dos mode is %d\n",mode));
+	if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
+		DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
+		return False;
+	}
+
+	file_size = get_file_size(sbuf);
+	allocation_size = get_allocation_size(NULL,&sbuf);
+	mdate = sbuf.st_mtime;
+	adate = sbuf.st_atime;
+	cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+
+	if (lp_dos_filetime_resolution(SNUM(conn))) {
+		cdate &= ~1;
+		mdate &= ~1;
+		adate &= ~1;
+	}
+
+	if(mode & aDIR)
+		file_size = 0;
+
+	nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
+
+	switch (info_level) {
+		case SMB_INFO_STANDARD:
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_INFO_STANDARD\n"));
+			if(requires_resume_key) {
+				SIVAL(p,0,reskey);
+				p += 4;
+			}
+			put_dos_date2(p,l1_fdateCreation,cdate);
+			put_dos_date2(p,l1_fdateLastAccess,adate);
+			put_dos_date2(p,l1_fdateLastWrite,mdate);
+			SIVAL(p,l1_cbFile,(uint32)file_size);
+			SIVAL(p,l1_cbFileAlloc,(uint32)allocation_size);
+			SSVAL(p,l1_attrFile,mode);
+			p += l1_achName;
+			nameptr = p;
+			p += align_string(outbuf, p, 0);
+			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
+			if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
+				if (len > 2) {
+					SCVAL(nameptr, -1, len - 2);
+				} else {
+					SCVAL(nameptr, -1, 0);
+				}
+			} else {
+				if (len > 1) {
+					SCVAL(nameptr, -1, len - 1);
+				} else {
+					SCVAL(nameptr, -1, 0);
+				}
+			}
+			p += len;
+			break;
+
+		case SMB_INFO_QUERY_EA_SIZE:
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_INFO_QUERY_EA_SIZE\n"));
+			if(requires_resume_key) {
+				SIVAL(p,0,reskey);
+				p += 4;
+			}
+			put_dos_date2(p,l2_fdateCreation,cdate);
+			put_dos_date2(p,l2_fdateLastAccess,adate);
+			put_dos_date2(p,l2_fdateLastWrite,mdate);
+			SIVAL(p,l2_cbFile,(uint32)file_size);
+			SIVAL(p,l2_cbFileAlloc,(uint32)allocation_size);
+			SSVAL(p,l2_attrFile,mode);
+			{
+				unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+				SIVAL(p,l2_cbList,ea_size); /* Extended attributes */
+			}
+			p += l2_achName;
+			nameptr = p - 1;
+			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE | STR_NOALIGN);
+			if (SVAL(outbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS) {
+				if (len > 2) {
+					len -= 2;
+				} else {
+					len = 0;
+				}
+			} else {
+				if (len > 1) {
+					len -= 1;
+				} else {
+					len = 0;
+				}
+			}
+			SCVAL(nameptr,0,len);
+			p += len;
+			SCVAL(p,0,0); p += 1; /* Extra zero byte ? - why.. */
+			break;
+
+		case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
+			was_8_3 = mangle_is_8_3(fname, True);
+			p += 4;
+			SIVAL(p,0,reskey); p += 4;
+			put_long_date(p,cdate); p += 8;
+			put_long_date(p,adate); p += 8;
+			put_long_date(p,mdate); p += 8;
+			put_long_date(p,mdate); p += 8;
+			SOFF_T(p,0,file_size); p += 8;
+			SOFF_T(p,0,allocation_size); p += 8;
+			SIVAL(p,0,nt_extmode); p += 4;
+			q = p; p += 4; /* q is placeholder for name length. */
+			{
+				unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+				SIVAL(p,0,ea_size); /* Extended attributes */
+				p += 4;
+			}
+			/* Clear the short name buffer. This is
+			 * IMPORTANT as not doing so will trigger
+			 * a Win2k client bug. JRA.
+			 */
+			memset(p,'\0',26);
+			if (!was_8_3 && lp_manglednames(SNUM(conn))) {
+				pstring mangled_name;
+				pstrcpy(mangled_name, fname);
+				mangle_map(mangled_name,True,True,SNUM(conn));
+				mangled_name[12] = 0;
+				len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
+				SSVAL(p, 0, len);
+			} else {
+				SSVAL(p,0,0);
+				*(p+2) = 0;
+			}
+			p += 2 + 24;
+			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+			SIVAL(q,0,len);
+			p += len;
+			len = PTR_DIFF(p, pdata);
+			len = (len + 3) & ~3;
+			SIVAL(pdata,0,len);
+			p = pdata + len;
+			break;
+
+		case SMB_FIND_FILE_DIRECTORY_INFO:
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
+			p += 4;
+			SIVAL(p,0,reskey); p += 4;
+			put_long_date(p,cdate); p += 8;
+			put_long_date(p,adate); p += 8;
+			put_long_date(p,mdate); p += 8;
+			put_long_date(p,mdate); p += 8;
+			SOFF_T(p,0,file_size); p += 8;
+			SOFF_T(p,0,allocation_size); p += 8;
+			SIVAL(p,0,nt_extmode); p += 4;
+			len = srvstr_push(outbuf, p + 4, fname, -1, STR_TERMINATE_ASCII);
+			SIVAL(p,0,len);
+			p += 4 + len;
+			len = PTR_DIFF(p, pdata);
+			len = (len + 3) & ~3;
+			SIVAL(pdata,0,len);
+			p = pdata + len;
+			break;
+      
+		case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
+			p += 4;
+			SIVAL(p,0,reskey); p += 4;
+			put_long_date(p,cdate); p += 8;
+			put_long_date(p,adate); p += 8;
+			put_long_date(p,mdate); p += 8;
+			put_long_date(p,mdate); p += 8;
+			SOFF_T(p,0,file_size); p += 8;
+			SOFF_T(p,0,allocation_size); p += 8;
+			SIVAL(p,0,nt_extmode); p += 4;
+			q = p; p += 4; /* q is placeholder for name length. */
+			{
+				unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+				SIVAL(p,0,ea_size); /* Extended attributes */
+				p +=4;
+			}
+			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+			SIVAL(q, 0, len);
+			p += len;
+
+			len = PTR_DIFF(p, pdata);
+			len = (len + 3) & ~3;
+			SIVAL(pdata,0,len);
+			p = pdata + len;
+			break;
+
+		case SMB_FIND_FILE_NAMES_INFO:
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
+			p += 4;
+			SIVAL(p,0,reskey); p += 4;
+			p += 4;
+			/* this must *not* be null terminated or w2k gets in a loop trying to set an
+			   acl on a dir (tridge) */
+			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+			SIVAL(p, -4, len);
+			p += len;
+			len = PTR_DIFF(p, pdata);
+			len = (len + 3) & ~3;
+			SIVAL(pdata,0,len);
+			p = pdata + len;
+			break;
+
+		case SMB_FIND_ID_FULL_DIRECTORY_INFO:
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
+			p += 4;
+			SIVAL(p,0,reskey); p += 4;
+			put_long_date(p,cdate); p += 8;
+			put_long_date(p,adate); p += 8;
+			put_long_date(p,mdate); p += 8;
+			put_long_date(p,mdate); p += 8;
+			SOFF_T(p,0,file_size); p += 8;
+			SOFF_T(p,0,allocation_size); p += 8;
+			SIVAL(p,0,nt_extmode); p += 4;
+			q = p; p += 4; /* q is placeholder for name length. */
+			{
+				unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+				SIVAL(p,0,ea_size); /* Extended attributes */
+				p +=4;
+			}
+			SIVAL(p,0,0); p += 4; /* Unknown - reserved ? */
+			SIVAL(p,0,sbuf.st_dev); p += 4;
+			SIVAL(p,0,sbuf.st_ino); p += 4;
+			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+			SIVAL(q, 0, len);
+			p += len; 
+			len = PTR_DIFF(p, pdata);
+			len = (len + 3) & ~3;
+			SIVAL(pdata,0,len);
+			p = pdata + len;
+			break;
+
+		case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
+			was_8_3 = mangle_is_8_3(fname, True);
+			p += 4;
+			SIVAL(p,0,reskey); p += 4;
+			put_long_date(p,cdate); p += 8;
+			put_long_date(p,adate); p += 8;
+			put_long_date(p,mdate); p += 8;
+			put_long_date(p,mdate); p += 8;
+			SOFF_T(p,0,file_size); p += 8;
+			SOFF_T(p,0,allocation_size); p += 8;
+			SIVAL(p,0,nt_extmode); p += 4;
+			q = p; p += 4; /* q is placeholder for name length */
+			{
+				unsigned int ea_size = estimate_ea_size(conn, NULL, pathreal);
+				SIVAL(p,0,ea_size); /* Extended attributes */
+				p +=4;
+			}
+			/* Clear the short name buffer. This is
+			 * IMPORTANT as not doing so will trigger
+			 * a Win2k client bug. JRA.
+			 */
+			memset(p,'\0',26);
+			if (!was_8_3 && lp_manglednames(SNUM(conn))) {
+				pstring mangled_name;
+				pstrcpy(mangled_name, fname);
+				mangle_map(mangled_name,True,True,SNUM(conn));
+				mangled_name[12] = 0;
+				len = srvstr_push(outbuf, p+2, mangled_name, 24, STR_UPPER|STR_UNICODE);
+				SSVAL(p, 0, len);
+			} else {
+				SSVAL(p,0,0);
+				*(p+2) = 0;
+			}
+			p += 26;
+			SSVAL(p,0,0); p += 2; /* Reserved ? */
+			SIVAL(p,0,sbuf.st_dev); p += 4;
+			SIVAL(p,0,sbuf.st_ino); p += 4;
+			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE_ASCII);
+			SIVAL(q,0,len);
+			p += len;
+			len = PTR_DIFF(p, pdata);
+			len = (len + 3) & ~3;
+			SIVAL(pdata,0,len);
+			p = pdata + len;
+			break;
+
+		/* CIFS UNIX Extension. */
+
+		case SMB_FIND_FILE_UNIX:
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
+			p+= 4;
+			SIVAL(p,0,reskey); p+= 4;    /* Used for continuing search. */
+
+			/* Begin of SMB_QUERY_FILE_UNIX_BASIC */
+			SOFF_T(p,0,get_file_size(sbuf));             /* File size 64 Bit */
+			p+= 8;
+
+			SOFF_T(p,0,get_allocation_size(NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */
+			p+= 8;
+
+			put_long_date(p,sbuf.st_ctime);       /* Inode change Time 64 Bit */
+			put_long_date(p+8,sbuf.st_atime);     /* Last access time 64 Bit */
+			put_long_date(p+16,sbuf.st_mtime);    /* Last modification time 64 Bit */
+			p+= 24;
+
+			SIVAL(p,0,sbuf.st_uid);               /* user id for the owner */
+			SIVAL(p,4,0);
+			p+= 8;
+
+			SIVAL(p,0,sbuf.st_gid);               /* group id of owner */
+			SIVAL(p,4,0);
+			p+= 8;
+
+			SIVAL(p,0,unix_filetype(sbuf.st_mode));
+			p+= 4;
+
+			SIVAL(p,0,unix_dev_major(sbuf.st_rdev));   /* Major device number if type is device */
+			SIVAL(p,4,0);
+			p+= 8;
+
+			SIVAL(p,0,unix_dev_minor(sbuf.st_rdev));   /* Minor device number if type is device */
+			SIVAL(p,4,0);
+			p+= 8;
+
+			SINO_T(p,0,(SMB_INO_T)sbuf.st_ino);   /* inode number */
+			p+= 8;
+
+			SIVAL(p,0, unix_perms_to_wire(sbuf.st_mode));     /* Standard UNIX file permissions */
+			SIVAL(p,4,0);
+			p+= 8;
+
+			SIVAL(p,0,sbuf.st_nlink);             /* number of hard links */
+			SIVAL(p,4,0);
+			p+= 8;
+
+			len = srvstr_push(outbuf, p, fname, -1, STR_TERMINATE);
+			p += len;
+
+			len = PTR_DIFF(p, pdata);
+			len = (len + 3) & ~3;
+			SIVAL(pdata,0,len);	/* Offset from this structure to the beginning of the next one */
+			p = pdata + len;
+			/* End of SMB_QUERY_FILE_UNIX_BASIC */
+
+			break;
+
+		default:      
+			return(False);
+	}
+	DEBUG(10,("at exit: conn 0x%p, outbuf 0x%p, ppdata 0x%p, pp 0x%p, "
+			"fname %s, pathreal %s, dirtype %d, info_level %d, "
+			"requires_resume_key %d, base_data 0x%p\n",
+			conn, outbuf, ppdata, pp, fname, pathreal, dirtype, 
+			info_level, requires_resume_key, base_data));
+	DEBUG(10,("at exit: pdata = 0x%p, p = 0x%p\n", pdata, p));
+	*ppdata = pdata;
+	*pp = p;
+	*last_name_off = PTR_DIFF(nameptr,base_data); 
+	return(True);
+}
+    
-------------- next part --------------
diff -Naur samba-3.0.8.orig/source/smbd/trans2.c samba-3.0.8/source/smbd/trans2.c
--- samba-3.0.8.orig/source/smbd/trans2.c	2004-11-07 14:43:23.000000000 -0600
+++ samba-3.0.8/source/smbd/trans2.c	2004-12-10 15:43:50.000000000 -0600
@@ -815,172 +815,61 @@
 	}
 }
 
-/****************************************************************************
- Get a level dependent lanman2 dir entry.
-****************************************************************************/
-
-static BOOL get_lanman2_dir_entry(connection_struct *conn,
-				  void *inbuf, void *outbuf,
-				 char *path_mask,int dirtype,int info_level,
-				 int requires_resume_key,
-				 BOOL dont_descend,char **ppdata, 
-				 char *base_data, int space_remaining, 
-				 BOOL *out_of_space, BOOL *got_exact_match,
-				 int *last_name_off)
+/**************************************************************************
+ * Actually opulate the lanman buffer pointed to by *ppdata.  Split out
+ * of get_lanman2_dir_entry so that we could short-circuit the dirptr
+ * operations where possible.
+ **************************************************************************/
+static BOOL populate_lanman2_dir_entry(connection_struct *conn, 
+				void *outbuf, char** ppdata, char** pp,
+				pstring fname, pstring pathreal,
+				int dirtype, int info_level,
+				int requires_resume_key,
+				SMB_STRUCT_STAT sbuf, char* base_data, int* last_name_off)
 {
-	const char *dname;
-	BOOL found = False;
-	SMB_STRUCT_STAT sbuf;
-	pstring mask;
-	pstring pathreal;
-	pstring fname;
-	char *p, *q, *pdata = *ppdata;
-	uint32 reskey=0;
-	int prev_dirpos=0;
-	int mode=0;
-	SMB_OFF_T file_size = 0;
-	SMB_BIG_UINT allocation_size = 0;
-	uint32 len;
-	time_t mdate=0, adate=0, cdate=0;
-	char *nameptr;
-	BOOL was_8_3;
+	BOOL was_8_3 = False;
+	SMB_OFF_T file_size;
+	SMB_BIG_UINT allocation_size;
+	int len = 0;
+	char *pdata = *ppdata;
+	char *p = *pp;
+	char *nameptr = p;
+	char *q;
+	int mode;
+	int cdate, mdate, adate;
 	int nt_extmode; /* Used for NT connections instead of mode */
-	BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
-
-	*fname = 0;
-	*out_of_space = False;
-	*got_exact_match = False;
-
-	if (!conn->dirptr)
-		return(False);
-
-	p = strrchr_m(path_mask,'/');
-	if(p != NULL) {
-		if(p[1] == '\0')
-			pstrcpy(mask,"*.*");
-		else
-			pstrcpy(mask, p+1);
-	} else
-		pstrcpy(mask, path_mask);
-
-	while (!found) {
-		BOOL got_match;
-
-		/* Needed if we run out of space */
-		prev_dirpos = TellDir(conn->dirptr);
-		dname = ReadDirName(conn->dirptr);
-
-		/*
-		 * Due to bugs in NT client redirectors we are not using
-		 * resume keys any more - set them to zero.
-		 * Check out the related comments in findfirst/findnext.
-		 * JRA.
-		 */
-
-		reskey = 0;
-
-		DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
-			(long)conn->dirptr,TellDir(conn->dirptr)));
-      
-		if (!dname) 
-			return(False);
-
-		pstrcpy(fname,dname);      
-
-		if(!(got_match = *got_exact_match = exact_match(fname, mask, conn->case_sensitive)))
-			got_match = mask_match(fname, mask, conn->case_sensitive);
-
-		if(!got_match && !mangle_is_8_3(fname, False)) {
-
-			/*
-			 * It turns out that NT matches wildcards against
-			 * both long *and* short names. This may explain some
-			 * of the wildcard wierdness from old DOS clients
-			 * that some people have been seeing.... JRA.
-			 */
-
-			pstring newname;
-			pstrcpy( newname, fname);
-			mangle_map( newname, True, False, SNUM(conn));
-			if(!(got_match = *got_exact_match = exact_match(newname, mask, conn->case_sensitive)))
-				got_match = mask_match(newname, mask, conn->case_sensitive);
-		}
-
-		if(got_match) {
-			BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
-			if (dont_descend && !isdots)
-				continue;
-	  
-			pstrcpy(pathreal,conn->dirpath);
-			if(needslash)
-				pstrcat(pathreal,"/");
-			pstrcat(pathreal,dname);
+	uint32 reskey = 0;
 
-			if (INFO_LEVEL_IS_UNIX(info_level)) {
-				if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) {
-					DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n",
-						pathreal,strerror(errno)));
-					continue;
-				}
-			} else if (SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
+	DEBUG(10,("conn 0x%p, outbuf 0x%p, ppdata 0x%p, pp 0x%p, fname %s, pathreal %s, dirtype %d, info_level %d, requires_resume_key %d, base_data 0x%p\n",
+				conn, outbuf, ppdata, pp, fname, pathreal, dirtype, info_level, requires_resume_key, base_data));
 
-				/* Needed to show the msdfs symlinks as 
-				 * directories */
-
-				if(lp_host_msdfs() && 
-				   lp_msdfs_root(SNUM(conn)) &&
-				   is_msdfs_link(conn, pathreal, NULL, NULL,
-						 &sbuf)) {
-
-					DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal));
-					sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
-
-				} else {
-
-					DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",
-						pathreal,strerror(errno)));
-					continue;
-				}
-			}
-
-			mode = dos_mode(conn,pathreal,&sbuf);
-
-			if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
-				DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
-				continue;
-			}
-
-			file_size = get_file_size(sbuf);
-			allocation_size = get_allocation_size(NULL,&sbuf);
-			mdate = sbuf.st_mtime;
-			adate = sbuf.st_atime;
-			cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
-
-			if (lp_dos_filetime_resolution(SNUM(conn))) {
-				cdate &= ~1;
-				mdate &= ~1;
-				adate &= ~1;
-			}
+	mode = dos_mode(conn,pathreal,&sbuf);
+	DEBUG(5,("dos mode is %d\n",mode));
+	if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
+		DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
+		return False;
+	}
 
-			if(mode & aDIR)
-				file_size = 0;
+	file_size = get_file_size(sbuf);
+	allocation_size = get_allocation_size(NULL,&sbuf);
+	mdate = sbuf.st_mtime;
+	adate = sbuf.st_atime;
+	cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
 
-			DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
-	  
-			found = True;
-		}
+	if (lp_dos_filetime_resolution(SNUM(conn))) {
+		cdate &= ~1;
+		mdate &= ~1;
+		adate &= ~1;
 	}
 
-	mangle_map(fname,False,True,SNUM(conn));
-
-	p = pdata;
-	nameptr = p;
+	if(mode & aDIR)
+		file_size = 0;
 
 	nt_extmode = mode ? mode : FILE_ATTRIBUTE_NORMAL;
 
 	switch (info_level) {
 		case SMB_INFO_STANDARD:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_STANDARD\n"));
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_INFO_STANDARD\n"));
 			if(requires_resume_key) {
 				SIVAL(p,0,reskey);
 				p += 4;
@@ -1012,7 +901,7 @@
 			break;
 
 		case SMB_INFO_QUERY_EA_SIZE:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_INFO_QUERY_EA_SIZE\n"));
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_INFO_QUERY_EA_SIZE\n"));
 			if(requires_resume_key) {
 				SIVAL(p,0,reskey);
 				p += 4;
@@ -1049,7 +938,7 @@
 			break;
 
 		case SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_BOTH_DIRECTORY_INFO\n"));
 			was_8_3 = mangle_is_8_3(fname, True);
 			p += 4;
 			SIVAL(p,0,reskey); p += 4;
@@ -1093,7 +982,7 @@
 			break;
 
 		case SMB_FIND_FILE_DIRECTORY_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_DIRECTORY_INFO\n"));
 			p += 4;
 			SIVAL(p,0,reskey); p += 4;
 			put_long_date(p,cdate); p += 8;
@@ -1113,7 +1002,7 @@
 			break;
       
 		case SMB_FIND_FILE_FULL_DIRECTORY_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_FULL_DIRECTORY_INFO\n"));
 			p += 4;
 			SIVAL(p,0,reskey); p += 4;
 			put_long_date(p,cdate); p += 8;
@@ -1140,7 +1029,7 @@
 			break;
 
 		case SMB_FIND_FILE_NAMES_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_NAMES_INFO\n"));
 			p += 4;
 			SIVAL(p,0,reskey); p += 4;
 			p += 4;
@@ -1156,7 +1045,7 @@
 			break;
 
 		case SMB_FIND_ID_FULL_DIRECTORY_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_ID_FULL_DIRECTORY_INFO\n"));
 			p += 4;
 			SIVAL(p,0,reskey); p += 4;
 			put_long_date(p,cdate); p += 8;
@@ -1185,7 +1074,7 @@
 			break;
 
 		case SMB_FIND_ID_BOTH_DIRECTORY_INFO:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_ID_BOTH_DIRECTORY_INFO\n"));
 			was_8_3 = mangle_is_8_3(fname, True);
 			p += 4;
 			SIVAL(p,0,reskey); p += 4;
@@ -1234,7 +1123,7 @@
 		/* CIFS UNIX Extension. */
 
 		case SMB_FIND_FILE_UNIX:
-			DEBUG(10,("get_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
+			DEBUG(10,("populate_lanman2_dir_entry: SMB_FIND_FILE_UNIX\n"));
 			p+= 4;
 			SIVAL(p,0,reskey); p+= 4;    /* Used for continuing search. */
 
@@ -1294,8 +1183,170 @@
 		default:      
 			return(False);
 	}
+	DEBUG(10,("at exit: conn 0x%p, outbuf 0x%p, ppdata 0x%p, pp 0x%p, "
+			"fname %s, pathreal %s, dirtype %d, info_level %d, "
+			"requires_resume_key %d, base_data 0x%p\n",
+			conn, outbuf, ppdata, pp, fname, pathreal, dirtype, 
+			info_level, requires_resume_key, base_data));
+	DEBUG(10,("at exit: pdata = 0x%p, p = 0x%p\n", pdata, p));
+	*ppdata = pdata;
+	*pp = p;
+	*last_name_off = PTR_DIFF(nameptr,base_data); 
+	return(True);
+}
+    
+
+/****************************************************************************
+ Get a level dependent lanman2 dir entry.
+****************************************************************************/
+
+static BOOL get_lanman2_dir_entry(connection_struct *conn,
+				  void *inbuf, void *outbuf,
+				 char *path_mask,int dirtype,int info_level,
+				 int requires_resume_key,
+				 BOOL dont_descend,char **ppdata, 
+				 char *base_data, int space_remaining, 
+				 BOOL *out_of_space, BOOL *got_exact_match,
+				 int *last_name_off)
+{
+	const char *dname;
+	BOOL found = False;
+	SMB_STRUCT_STAT sbuf;
+	pstring mask;
+	pstring pathreal;
+	pstring fname;
+	char *p, *pdata = *ppdata;
+	uint32 reskey=0;
+	int prev_dirpos=0;
+	int mode=0;
+	char *nameptr;
+	BOOL needslash = ( conn->dirpath[strlen(conn->dirpath) -1] != '/');
+
+	*fname = 0;
+	*out_of_space = False;
+	*got_exact_match = False;
+
+	if (!conn->dirptr)
+		return(False);
+
+	p = strrchr_m(path_mask,'/');
+	if(p != NULL) {
+		if(p[1] == '\0')
+			pstrcpy(mask,"*.*");
+		else
+			pstrcpy(mask, p+1);
+	} else
+		pstrcpy(mask, path_mask);
+
+	while (!found) {
+		BOOL got_match;
+
+		/* Needed if we run out of space */
+		prev_dirpos = TellDir(conn->dirptr);
+		dname = ReadDirName(conn->dirptr);
+
+		/*
+		 * Due to bugs in NT client redirectors we are not using
+		 * resume keys any more - set them to zero.
+		 * Check out the related comments in findfirst/findnext.
+		 * JRA.
+		 */
+
+		reskey = 0;
+
+		DEBUG(8,("get_lanman2_dir_entry:readdir on dirptr 0x%lx now at offset %d\n",
+			(long)conn->dirptr,TellDir(conn->dirptr)));
+      
+		if (!dname) 
+			return(False);
+
+		pstrcpy(fname,dname);      
+
+		if(!(got_match = *got_exact_match = exact_match(fname, mask, conn->case_sensitive)))
+			got_match = mask_match(fname, mask, conn->case_sensitive);
+
+		if(!got_match && !mangle_is_8_3(fname, False)) {
+
+			/*
+			 * It turns out that NT matches wildcards against
+			 * both long *and* short names. This may explain some
+			 * of the wildcard wierdness from old DOS clients
+			 * that some people have been seeing.... JRA.
+			 */
+
+			pstring newname;
+			pstrcpy( newname, fname);
+			mangle_map( newname, True, False, SNUM(conn));
+			if(!(got_match = *got_exact_match = exact_match(newname, mask, conn->case_sensitive)))
+				got_match = mask_match(newname, mask, conn->case_sensitive);
+		}
+
+		if(got_match) {
+			BOOL isdots = (strequal(fname,"..") || strequal(fname,"."));
+			if (dont_descend && !isdots)
+				continue;
+	  
+			pstrcpy(pathreal,conn->dirpath);
+			if(needslash)
+				pstrcat(pathreal,"/");
+			pstrcat(pathreal,dname);
+
+			if (INFO_LEVEL_IS_UNIX(info_level)) {
+				if (SMB_VFS_LSTAT(conn,pathreal,&sbuf) != 0) {
+					DEBUG(5,("get_lanman2_dir_entry:Couldn't lstat [%s] (%s)\n",
+						pathreal,strerror(errno)));
+					continue;
+				}
+			} else if (SMB_VFS_STAT(conn,pathreal,&sbuf) != 0) {
+
+				/* Needed to show the msdfs symlinks as 
+				 * directories */
+
+				if(lp_host_msdfs() && 
+				   lp_msdfs_root(SNUM(conn)) &&
+				   is_msdfs_link(conn, pathreal, NULL, NULL,
+						 &sbuf)) {
+
+					DEBUG(5,("get_lanman2_dir_entry: Masquerading msdfs link %s as a directory\n", pathreal));
+					sbuf.st_mode = (sbuf.st_mode & 0xFFF) | S_IFDIR;
+
+				} else {
+
+					DEBUG(5,("get_lanman2_dir_entry:Couldn't stat [%s] (%s)\n",
+						pathreal,strerror(errno)));
+					continue;
+				}
+			}
+
+			DEBUG(5,("get_lanman2_dir_entry found %s fname=%s\n",pathreal,fname));
+
+			mode = dos_mode(conn,pathreal,&sbuf);
+	  
+			if (!dir_check_ftype(conn,mode,&sbuf,dirtype)) {
+				DEBUG(5,("[%s] attribs didn't match %x\n",fname,dirtype));
+				return False;
+			}
+			found = True;
+		}
+	}
+
+	mangle_map(fname,False,True,SNUM(conn));
 
+	p = pdata;
+	nameptr = p;
 
+	if(!populate_lanman2_dir_entry(conn, 
+			outbuf, ppdata, &p, 
+			fname, pathreal,
+			dirtype, info_level,
+			requires_resume_key, 
+			sbuf, base_data, last_name_off)) {
+		/* Some problem we should probably do a better job of handling... */
+		DEBUG(3,("populate_lanman2_dir_entry failed!"));
+		return False;
+	}
+			
+	
 	if (PTR_DIFF(p,pdata) > space_remaining) {
 		/* Move the dirptr back to prev_dirpos */
 		SeekDir(conn->dirptr, prev_dirpos);
@@ -1305,7 +1356,7 @@
 	}
 
 	/* Setup the last_filename pointer, as an offset from base_data */
-	*last_name_off = PTR_DIFF(nameptr,base_data);
+	/* *last_name_off = PTR_DIFF(nameptr,base_data); */
 	/* Advance the data pointer to the next slot */
 	*ppdata = p;
 
@@ -1424,84 +1475,124 @@
 		return ERROR_DOS(ERRDOS,ERRnomem);
 	*pparams = params;
 
-	dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
-	if (dptr_num < 0)
-		return(UNIXERROR(ERRDOS,ERRbadfile));
-
-	/* Save the wildcard match and attribs we are using on this directory - 
-		needed as lanman2 assumes these are being saved between calls */
-
-	if(!(wcard = strdup(mask))) {
-		dptr_close(&dptr_num);
-		return ERROR_DOS(ERRDOS,ERRnomem);
-	}
-
-	dptr_set_wcard(dptr_num, wcard);
-	dptr_set_attr(dptr_num, dirtype);
-
-	DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
-
-	/* We don't need to check for VOL here as this is returned by 
-		a different TRANS2 call. */
-  
-	DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn))));
-	if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
-		dont_descend = True;
-    
-	p = pdata;
-	space_remaining = max_data_bytes;
-	out_of_space = False;
-
-	for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
-		BOOL got_exact_match = False;
-
-		/* this is a heuristic to avoid seeking the dirptr except when 
-			absolutely necessary. It allows for a filename of about 40 chars */
-		if (space_remaining < DIRLEN_GUESS && numentries > 0) {
-			out_of_space = True;
-			finished = False;
-		} else {
-			finished = !get_lanman2_dir_entry(conn,
+	/* Optimization: if we are in case-sensitive mode and the mask contains
+	 * no wildcards, the file exists iff SMB_VFS_STAT can find it. MM */
+	if ((conn->case_sensitive && !ms_has_wild(mask)) 
+		&& (close_after_first || close_if_end)) {
+	    DEBUG(5,("case sensitive and no wilds; using VFS result\n"));
+	    /* stat buffer from unix_convert should still be valid here */
+	    if (sbuf.st_nlink == 0) {
+			DEBUG(5,("sbuf.st_nlink was 0 -> not found\n"));
+			return(ERROR_DOS(ERRDOS,ERRbadfile));
+	    } else {
+			pstring pathreal;
+			char* strp;
+			DEBUG(5,("sbuf.st_nlink was non-0 -> found\n"));
+			strp = pstrcpy(pathreal, directory);
+			strp = pstrcpy(strp, "/");
+			strp = pstrcpy(strp, mask);
+			dptr_num = -3; /* should really not be harcoded here */
+			numentries = 1;
+			finished = True;
+			p = pdata;
+			/* Fabricate a response without using the dirptr. */
+			populate_lanman2_dir_entry(conn,
+				outbuf, &pdata, &p, 
+				mask, pathreal,
+				dirtype, info_level,
+				requires_resume_key, 
+				sbuf, pdata, &last_name_off);
+	
+			/*finished = !get_lanman2_dir_entry(conn,
 					inbuf, outbuf,
 					mask,dirtype,info_level,
 					requires_resume_key,dont_descend,
 					&p,pdata,space_remaining, &out_of_space, &got_exact_match,
 					&last_name_off);
+					*/
+	    }
+	} else {
+		
+		dptr_num = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid));
+		if (dptr_num < 0)
+			return(UNIXERROR(ERRDOS,ERRbadfile));
+
+		/* Save the wildcard match and attribs we are using on this directory - 
+			needed as lanman2 assumes these are being saved between calls */
+
+		if(!(wcard = strdup(mask))) {
+			dptr_close(&dptr_num);
+			return ERROR_DOS(ERRDOS,ERRnomem);
 		}
 
-		if (finished && out_of_space)
-			finished = False;
+		dptr_set_wcard(dptr_num, wcard);
+		dptr_set_attr(dptr_num, dirtype);
 
-		if (!finished && !out_of_space)
-			numentries++;
+		DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, wcard, dirtype));
 
-		/*
-		 * As an optimisation if we know we aren't looking
-		 * for a wildcard name (ie. the name matches the wildcard exactly)
-		 * then we can finish on any (first) match.
-		 * This speeds up large directory searches. JRA.
-		 */
+		/* We don't need to check for VOL here as this is returned by 
+			a different TRANS2 call. */
+	  
+		DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n", conn->dirpath,lp_dontdescend(SNUM(conn))));
+		if (in_list(conn->dirpath,lp_dontdescend(SNUM(conn)),conn->case_sensitive))
+			dont_descend = True;
+		
+		p = pdata;
+		space_remaining = max_data_bytes;
+		out_of_space = False;
+
+		for (i=0;(i<maxentries) && !finished && !out_of_space;i++) {
+			BOOL got_exact_match = False;
+
+			/* this is a heuristic to avoid seeking the dirptr except when 
+				absolutely necessary. It allows for a filename of about 40 chars */
+			if (space_remaining < DIRLEN_GUESS && numentries > 0) {
+				out_of_space = True;
+				finished = False;
+			} else {
+				finished = !get_lanman2_dir_entry(conn,
+						inbuf, outbuf,
+						mask,dirtype,info_level,
+						requires_resume_key,dont_descend,
+						&p,pdata,space_remaining, &out_of_space, &got_exact_match,
+						&last_name_off);
+			}
 
-		if(got_exact_match)
-			finished = True;
+			if (finished && out_of_space)
+				finished = False;
 
-		space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
-	}
-  
-	/* Check if we can close the dirptr */
-	if(close_after_first || (finished && close_if_end)) {
-		DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
-		dptr_close(&dptr_num);
-	}
+			if (!finished && !out_of_space)
+				numentries++;
 
-	/* 
-	 * If there are no matching entries we must return ERRDOS/ERRbadfile - 
-	 * from observation of NT.
-	 */
+			/*
+			 * As an optimisation if we know we aren't looking
+			 * for a wildcard name (ie. the name matches the wildcard exactly)
+			 * then we can finish on any (first) match.
+			 * This speeds up large directory searches. JRA.
+			 */
+
+			if(got_exact_match)
+				finished = True;
+
+			space_remaining = max_data_bytes - PTR_DIFF(p,pdata);
+		}
+	  
+		/* Check if we can close the dirptr */
+		if(close_after_first || (finished && close_if_end)) {
+			DEBUG(5,("call_trans2findfirst - (2) closing dptr_num %d\n", dptr_num));
+			dptr_close(&dptr_num);
+		}
+
+		/* 
+		 * If there are no matching entries we must return ERRDOS/ERRbadfile - 
+		 * from observation of NT.
+		 */
+
+		if(numentries == 0) {
+			dptr_close(&dptr_num);
+			return ERROR_DOS(ERRDOS,ERRbadfile);
+		}
 
-	if(numentries == 0) {
-		dptr_close(&dptr_num);
-		return ERROR_DOS(ERRDOS,ERRbadfile);
 	}
 
 	/* At this point pdata points to numentries directory entries. */


More information about the samba-technical mailing list