clinuxoperating-systemfile-attributes

How to check for character files in a directory


I got this code from this post

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

void main()
{
    char* folder="/dev/input";                                     //folder to open

    DIR* dir_p;
    struct dirent* dir_element;
    struct stat file_info;

    // open directory
    dir_p=opendir(folder);

    // show some info for each file in given directory
    while(dir_element = readdir(dir_p)) {

        lstat(dir_element->d_name, &file_info);          //getting a file stats

        puts(dir_element->d_name);                       // show current filename
        printf("file mode: %d\n", file_info.st_mode);

        // print what kind of file we are dealing with
        if (file_info.st_mode == S_IFDIR) puts("|| directory");
        if (file_info.st_mode == S_IFREG) puts("|| regular file");
        if (file_info.st_mode == S_IFLNK) puts("|| symbolic link");
        if (S_ISCHR(file_info.st_mode)) puts("|| character file");
    }
}

I modified it a little bit so that it prints if files in /dev/input are character files or not. But when I run this(even with sudo) it only prints the file name, file mode and nothing else.


Solution

  • First, file_info.st_mode are bit-fields, so you should check if individual bits are set with the & operator.

    That is,

    if (file_info.st_mode & S_IFDIR) puts("|| directory");
    

    However, using S_ISXXX macros is more explicit as you did for the last one.

    Second, dir_element->d_name contains only the basename of the path. Hence, you should prepend folder to it before feeding it into lstat. If you have checked the return value of lstat, you could have known that it didn't succeed. So you can do something like

    // 2 is for '/' and '\0'
    char *full_path = malloc(strlen(folder) + strlen(dir_element->d_name) + 2;
    // please do check if malloc failed
    // I'm sure FULL_PATH has sufficient memory, but use strncpy/strncat if in doubt
    strcpy(full_path, folder);
    strcat(full_path, "/");
    strcat(full_path, dir_element->d_name);
    lstat(full_path, &file_info);
    free(full_path);