Is there a way to list all subdirectories in a given directory path in C? I was hoping I would be able to do it with the stat()
function but it only works on files.
views:
902answers:
4Thanks, I will give that a shot.
Kenji
2009-11-12 16:06:46
+2
A:
stat works on directories too.
int num_dirs(const char* path)
{
int dir_count = 0;
struct dirent* dent;
DIR* srcdir = opendir(path);
if (srcdir == NULL)
{
perror("opendir");
return -1;
}
while((dent = readdir(srcdir)) != NULL)
{
struct stat st;
if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0)
continue;
if (fstatat(dirfd(srcdir), dent->d_name, &st) < 0)
{
perror(dent->d_name);
continue;
}
if (S_ISDIR(st.st_mode)) dir_count++;
}
closedir(srcdir);
return dir_count;
}
sevity
2009-11-12 16:38:05
thanks, i man'd quite a bit of the functions you used to understand what was going on and it works!
Kenji
2009-11-12 21:10:56
Because this seemed like such a good answer, I've edited it slightly to make it a bit more robust - replacing `stat` with `fstatat` (which means you don't have to muck about creating the full path, and also avoid race conditions), and handling errors from `opendir` and `fstatat` (which are reasonably likely in practice - things like "permission denied").
caf
2009-11-13 00:07:38
+1
A:
As others have noted, stat(2)
works fine on files and devices of all types. It reads through symbolic links to the file at the far end; if you need the information about the symbolic link itself, use lstat(2)
.
To list the names of all directories within a single directory (non-recursively), use a combination of the readdir(3)
family of functions.
To list the names of all directories recursively, use the ftw(3)
or nftw(3)
functions to do a 'file tree walk' (from whence cometh their names; 'n' is for 'new').
Jonathan Leffler
2009-11-12 16:43:54
A:
/*
I had need in something like this not so long ago (my difference is I
needed recursive scan) so I added only some comments... Sorry for recursion
but I was short of time and this was only part of internal one-time tool.
*/
/* Print all the dirs starting from <path> [maybe recursive]. */
int print_dirs(const char *path, int recursive)
{
struct dirent *direntp = NULL;
DIR *dirp = NULL;
size_t path_len;
/* Check input parameters. */
if (!path)
return -1;
path_len = strlen(path);
if (!path || !path_len || (path_len > _POSIX_PATH_MAX))
return -1;
/* Open directory */
dirp = opendir(path);
if (dirp == NULL)
return -1;
while ((direntp = readdir(dirp)) != NULL)
{
/* For every directory entry... */
struct stat fstat;
char full_name[_POSIX_PATH_MAX + 1];
/* Calculate full name, check we are in file length limts */
if ((path_len + strlen(direntp->d_name) + 1) > _POSIX_PATH_MAX)
continue;
strcpy(full_name, path);
if (full_name[path_len - 1] != '/')
strcat(full_name, "/");
strcat(full_name, direntp->d_name);
/* Ignore special directories. */
if ((strcmp(direntp->d_name, ".") == 0) ||
(strcmp(direntp->d_name, "..") == 0))
continue;
/* Print only if it is really directory. */
if (stat(full_name, &fstat) < 0)
continue;
if (S_ISDIR(fstat.st_mode))
{
printf("%s\n", full_name);
if (recursive)
print_dirs(full_name, 1);
}
}
/* Finalize resources. */
(void)closedir(dirp);
return 0;
}
/* We are taking first argument as initial path name. */
int main(int argc, const char* argv[])
{
if (argc < 2)
return -1;
print_dirs(argv[1], 1);
return 0;
}
Roman Nikitchenko
2009-11-12 17:46:57