Question regarding libsmbclient.

Michael Davidson michael_davidson at pacbell.net
Sun May 27 19:37:02 GMT 2001


There are probably some things that need to be looked at in smbclient
itself, but there is a lot that could be improved in the application
code as well.

One obvious problem is that the code appears to call smbc_init() 
repeatedly, within each call to direcory_list(), is_file(), is_directory(),
etc. I'm not a libsmbclient expert but it looks as if this is both
unnecessary and harmful. Unnecessary because you only need to do it once,
and harmful because smbc_init() doesn't appear to be robust about being
called more than once and, at a quick glance, it looks as if it will,
among other things, malloc() a new copy of the smbc_file_table every
time it is called. This alone will be a massive memory leak (not to mention
that nothing will work properly).

So, just call smbc_init() once ...

After that, I think what you really want is something like the standard
UNIX ftw() function which walks a file tree calling a user defined callback
function for every file and directory that it finds.

I have attached a rough version of what this might look like - note that
it is pretty much untested, but you might find it useful either "as is"
or as an example of how it could be done.

md
 

> At 03:05 AM 5/27/01 -0700, Ray Van Dolson wrote:
> >I'm wondering if the fault is due to my shoddy C programming skills
> >(someone already has suggested I try jCIFS which I will) or a memory leak
> >or inefficiency in libsmbclient.so.  If someone a little more experienced
> >than I could discern this from glancing at my code, I'd sure appreciate
> >it.
> 
> OK, I doubt that it is you programming skills. The problem may be that in
> libsmbclient, when you open a directory, I slurp up all the entries in the
> directory into malloc'd structures ...
> 
> This is forced on my because I re-used a lower layer libsmb routine that
> expected to read the whole directory in one go and calls a call-back ...
> 
> Perhaps I need to defer reading the directory until smbc_getdents is
> called. I was wondering when this would bite, and perhaps it is now ...
>
-------------- next part --------------
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
#include <libsmbclient.h>

typedef int	(*callback_t)(const char *, struct stat *, int);
static int	smbc_ftw1(char *path, callback_t func);

/*
 * file tree walk for smbclient
 * 
 * similar to standard UNIX ftw() except:
 * - there is no 'depth' argument to smbc_ftw()
 * - the third argument to the callback function is 0
 *   if the contents of the stat structure are valid
 *   otherwise the value of errno with which stat() failed
 */
int
smbc_ftw(const char *path, callback_t func)
{
	char buf[SMBC_MAX_NAME+1];

	if (strlen(path) > SMBC_MAX_NAME) {
		errno = ENAMETOOLONG;
		return -1;
	}

	strcpy(buf, path);

	return smbc_ftw1(buf, func);
}


static int
smbc_ftw1(char *path, callback_t func)
{
	int			d;
	struct smbc_dirent	*dir;
	int			pathlen;
	int			rval    = 0;

	pathlen = strlen(path);
	if (pathlen >= SMBC_MAX_NAME) {
		errno = ENAMETOOLONG;
		return -1;
	}

	if ((d = smbc_opendir(path)) < 0) {
		return -1;
	}

	path[pathlen++] = '/';

	while ((dir = smbc_readdir(d)) != NULL) {
		struct stat	st;
		int		err;

		if (pathlen + dir->namelen > SMBC_MAX_NAME) {
			errno = ENAMETOOLONG;
			rval = -1;
			break;
		}

		strcpy(&path[pathlen], dir->name);

		if ((err = smbc_stat(path, &st)) != 0) {
			err = errno;
		}

		if ((rval = func(path, &st, err)) != 0) {
			break;
		}

		if (S_ISDIR(st.st_mode) && (strcmp(".", dir->name) != 0) &&
		   (strcmp("..", dir->name) != 0) ) {
			if ((rval = smbc_ftw1(path, func)) != 0) {
				break;
			}
		}
	}

	path[pathlen-1] = '\0';
	smbc_closedir(d);

	return rval;
}


More information about the samba-technical mailing list