[Samba] smbclient hangs

Jeremy Allison jra at samba.org
Tue May 31 23:26:03 GMT 2005


On Mon, May 30, 2005 at 05:09:15PM +0200, Mair Wolfgang-awm013 wrote:
> Hello,
> 
> I'm having problems with using smbclient on a win2k share. The server runs samba 3.0.14a on Solaris 9.
> 
> I want to tar the whole directory of a share. Into a file on the server
> 
> What I found out so far is, that it works until a maximum file count of 35. It is not size dependant but if the file count in that share exceeds more than 35 the smbclient hangs for ever and with the time is consuming up all the available memory. Until the server hangs as well due to a lack of memory space. 
> 
> Any ideas would be greatly appreciated.

This is probably the "infinate spin" reading directories
bug which we've fixed in SVN. Try this patch for 3.0.14a.

Jeremy
-------------- next part --------------
--- libsmb/clilist.c.orig	2005-04-13 23:14:24.000000000 -0700
+++ libsmb/clilist.c	2005-05-31 16:18:33.603556265 -0700
@@ -22,6 +22,8 @@
 
 #include "includes.h"
 
+extern file_info def_finfo;
+
 /****************************************************************************
  Interpret a long filename structure - this is mostly guesses at the moment.
  The length of the structure is returned
@@ -29,16 +31,20 @@
  by NT and 2 is used by OS/2
 ****************************************************************************/
 
-static size_t interpret_long_filename(struct cli_state *cli,
-				   int level,char *p,file_info *finfo)
+static size_t interpret_long_filename(struct cli_state *cli, int level,char *p,file_info *finfo,
+					uint32 *p_resume_key, DATA_BLOB *p_last_name_raw, uint32 *p_last_name_raw_len)
 {
-	extern file_info def_finfo;
 	file_info finfo2;
 	int len;
 	char *base = p;
 
-	if (!finfo) finfo = &finfo2;
+	if (!finfo) {
+		finfo = &finfo2;
+	}
 
+	if (p_resume_key) {
+		*p_resume_key = 0;
+	}
 	memcpy(finfo,&def_finfo,sizeof(*finfo));
 
 	switch (level) {
@@ -84,6 +90,10 @@
 		{
 			size_t namelen, slen;
 			p += 4; /* next entry offset */
+
+			if (p_resume_key) {
+				*p_resume_key = IVAL(p,0);
+			}
 			p += 4; /* fileindex */
 				
 			/* these dates appear to arrive in a
@@ -130,6 +140,22 @@
 			clistr_pull(cli, finfo->name, p,
 				    sizeof(finfo->name),
 				    namelen, 0);
+
+			/* To be robust in the face of unicode conversion failures
+			   we need to copy the raw bytes of the last name seen here.
+			   Namelen doesn't include the terminating unicode null, so
+			   copy it here. */
+
+			if (p_last_name_raw && p_last_name_raw_len) {
+				if (namelen + 2 > p_last_name_raw->length) {
+					memset(p_last_name_raw->data, '\0', sizeof(p_last_name_raw->length));
+					*p_last_name_raw_len = 0;
+				} else {
+					memcpy(p_last_name_raw->data, p, namelen);
+					SSVAL(p_last_name_raw->data, namelen, 0);
+					*p_last_name_raw_len = namelen + 2;
+				}
+			}
 			return (size_t)IVAL(base, 0);
 		}
 	}
@@ -145,7 +171,7 @@
 int cli_list_new(struct cli_state *cli,const char *Mask,uint16 attribute, 
 		 void (*fn)(const char *, file_info *, const char *, void *), void *state)
 {
-#if 0
+#if 1
 	int max_matches = 1366; /* Match W2k - was 512. */
 #else
 	int max_matches = 512;
@@ -169,6 +195,9 @@
 	uint16 setup;
 	pstring param;
 	const char *mnt;
+	uint32 resume_key = 0;
+	uint32 last_name_raw_len = 0;
+	DATA_BLOB last_name_raw = data_blob(NULL, 2*sizeof(pstring));
 
 	/* NT uses 260, OS/2 uses 2. Both accept 1. */
 	info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
@@ -203,13 +232,19 @@
 			SSVAL(param,0,ff_dir_handle);
 			SSVAL(param,2,max_matches); /* max count */
 			SSVAL(param,4,info_level); 
-			SIVAL(param,6,0); /* ff_resume_key */
+			/* For W2K servers serving out FAT filesystems we *must* set the
+			   resume key. If it's not FAT then it's returned as zero. */
+			SIVAL(param,6,resume_key); /* ff_resume_key */
 			/* NB. *DON'T* use continue here. If you do it seems that W2K and bretheren
 			   can miss filenames. Use last filename continue instead. JRA */
 			SSVAL(param,10,(FLAG_TRANS2_FIND_REQUIRE_RESUME|FLAG_TRANS2_FIND_CLOSE_IF_END));	/* resume required + close on end */
 			p = param+12;
-			p += clistr_push(cli, param+12, mask, sizeof(param)-12, 
-					 STR_TERMINATE);
+			if (last_name_raw_len && (last_name_raw_len < (sizeof(param)-12))) {
+				memcpy(p, last_name_raw.data, last_name_raw_len);
+				p += last_name_raw_len;
+			} else {
+				p += clistr_push(cli, param+12, mask, sizeof(param)-12, STR_TERMINATE);
+			}
 		}
 
 		param_len = PTR_DIFF(p, param);
@@ -276,7 +311,8 @@
 				/* Last entry - fixup the last offset length. */
 				SIVAL(p2,0,PTR_DIFF((rdata + data_len),p2));
 			}
-			p2 += interpret_long_filename(cli,info_level,p2,&finfo);
+			p2 += interpret_long_filename(cli,info_level,p2,&finfo,
+							&resume_key,&last_name_raw,&last_name_raw_len);
 		}
 
 		if (ff_lastname > 0) {
@@ -316,12 +352,13 @@
 	mnt = cli_cm_get_mntpoint( cli );
 
 	for (p=dirlist,i=0;i<total_received;i++) {
-		p += interpret_long_filename(cli,info_level,p,&finfo);
+		p += interpret_long_filename(cli,info_level,p,&finfo,NULL,NULL,NULL);
 		fn( mnt,&finfo, Mask, state );
 	}
 
-	/* free up the dirlist buffer */
+	/* free up the dirlist buffer and last name raw blob */
 	SAFE_FREE(dirlist);
+	data_blob_free(&last_name_raw);
 	return(total_received);
 }
 
@@ -332,7 +369,6 @@
 
 static int interpret_short_filename(struct cli_state *cli, char *p,file_info *finfo)
 {
-	extern file_info def_finfo;
 
 	*finfo = def_finfo;
 


More information about the samba mailing list