Search code examples
crecursionfile-listing

C - Ignore subdirectories names and only print files names


With this code I'm able to print recursively all files and subdirectories from a given path.

What I want is to ignore (not print) all the subdirectorynames, and only print the file names.

This is the code:

#include <stdio.h>
#include <dirent.h>
#include <string.h> 


void listFilesRecursively(char *basePath)
{
    char path[1000];
    struct dirent *dp;
    DIR *dir = opendir(basePath);

    if (!dir)
        return;

    while ((dp = readdir(dir)) != NULL)
    {
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0)
        {
            strcpy(path, basePath);
            strcat(path, "/");
            strcat(path, dp->d_name);

            listFilesRecursively(path);
            printf("%s\n", path);
        }
    }

    closedir(dir);
}

int main()
{
    char path[100];

    printf("Enter path to list files: ");
    scanf("%s", path);

    listFilesRecursively(path);

    return 0;
}

Solution

  • There are macros that tells you what type of file it is:

    • S_ISREG(): regular file
    • S_ISDIR(): directory file
    • S_ISCHR(): character special file
    • S_ISBLK(): block special file
    • S_ISFIFO(): pipe or FIFO -S_ISLNK(): symbolic
    • S_ISSOCK(): link socket

    First of all you can use one of the following functions to get informaration:

    #include <sys/stat.h>
    int stat(const char *restrict pathname, struct stat *restrict buf );
    int fstat(int fd, struct stat *buf);
    int lstat(const char *restrict pathname, struct stat *restrict buf );
    int fstatat(int fd, const char *restrict pathname, struct stat *restrict buf, int flag);
    

    From the Advanced Programming in Unix Environment book:

    Given a pathname, the stat function returns a structure of information about the named file. The fstat function obtains information about the file that is already open on the descriptor fd. The lstat function is similar to stat, but when the named file is a symbolic link, lstat returns information about the symbolic link, not the file referenced by the symbolic link.

    You can try something like the following:

    struct stat statbuf;
    struct dirent *dirp;
    DIR *dp;
    int ret, n;
    /* fullpath contains full pathname for every file */
    if (lstat(fullpath, &statbuf) < 0)
    {
        printf("error\n");
        //return if you want
    }
    if (S_ISDIR(statbuf.st_mode) == 0)
    {
       /* not a directory */
    }
    else
    {
       //a directory
    }
    

    Historically, early versions of the UNIX System didn’t provide the S_ISxxx macros. Instead, we had to logically AND the st_mode value with the mask S_IFMT and then compare the result with the constants whose names are S_IFxxx. Most systems define this mask and the related constants in the file .

    For example:

    struct stat *statptr;
    if (lstat(fullpath, statptr) < 0)
    {
        printf("error\n");
        //return if you want
    }
    switch (statptr->st_mode & S_IFMT) {
        case S_IFREG:  ...
        case S_IFBLK:  ...
        case S_IFCHR:  ...
        case S_IFIFO:  ...
        case S_IFLNK:  ...
        case S_IFSOCK: ... 
        case S_IFDIR:  ... 
        }