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