C - Scandir only fill namelist with folders

3.6k views Asked by At

How do I use scandir, so that it only fills my struct dirent ** namelist, with folders?

1

There are 1 answers

4
M Oehm On

You can filter the entities to list by providing a filter function, which should return a non-zero value if the file is to be included in the list.

Unfortunately, the members of the dirent struct don't tell you whether you have a directory or not (although your system might include a type field), so you must use some other means to find directories, for example stat:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

int filter_dir(const struct dirent *e)
{
    struct stat st;

    stat(e->d_name, &st);
    return (st.st_mode & S_IFDIR);
}

You could also try to call opendir on the name and check wheter that succeeds. (But don't forget to close it if it is successful.)

This works for the current directory, because the names exclude the path. The filter also doesn't provide a slot for passing additional data, so the best you can do is to define a global variable that holds the path and that you must set beforehand.

Here's an implementation with a wrapper function, scandir_dir:

#include <stdlib.h>
#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

static const char *filterdir;

static int filter_dir(const struct dirent *e)
{
    char buf[NAME_MAX];
    struct stat st;

    if (filterdir) {
        snprintf(buf, sizeof(buf), "%s/%s", filterdir, e->d_name);    
        stat(buf, &st);
    } else {    
        stat(e->d_name, &st);
    }
    return (st.st_mode & S_IFDIR);
}

int scandir_dir(const char *path, struct dirent ***namelist)
{
    int n;

    filterdir = path;
    n = scandir(path, namelist, filter_dir, alphasort);
    filterdir = NULL;

    return n;
}

int main()
{
    struct dirent **namelist;
    int n;

    n = scandir_dir("/some/dir", &namelist);

    if (n < 0) {
        perror("scandir");
    } else {
        int i;

        for (i = 0; i < n; i++) {
            printf("%s\n", namelist[i]->d_name);
            free(namelist[i]);
        }
        free(namelist);
    }

    return 0;
}