C: Checking the type of a file. Using lstat() and macros doesn't work
Asked Answered
B

3

6

I use opendir() to open a directory and then readdir() and lstat() to get the stats of each file in that directory. Following this manpage I wrote the code under which doesn't work as thought. It does list all the files in the current directory but it doesn't print out whever the file is a regular file, a symlink or a directory.

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

void main(){

    char* folder=".";                                     //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");
    }

}
Busch answered 6/10, 2011 at 12:33 Comment(1)
Has anybody told you yet that main() should return int?Lolita
E
8

I Know it is years later but for posterity you were doing it wrong:
@alk was right the st_mode field carries more info e.g file type,file permissions,etc
To extract file type you perform bitwise and on the st_mode field and the file type mask S_IFMT .Then check the result for whatever you wanted. That is what the macros mentioned by @Ernest Friedman-Hill do. A swicth is better suited for a comprehensive check i.e

for a simple case:

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

for a comprehensive check:

       struct stat st;
       ...

      switch (st.st_mode & S_IFMT) {
        case S_IFREG:  
            puts("|| regular file");
            break;
        case S_IFDIR:
            puts("|| directory");
            break;
        case S_IFCHR:        
            puts("|| character device");
            break;
        case S_IFBLK:        
            puts("|| block device");
            break;
        case S_IFLNK: 
            puts("|| symbolic link");
            break;
        case S_IFIFO: 
            puts("|| pipe");    
            break;
        case S_IFSOCK:
            puts("|| socket");
            break;
        default:
            puts("|| unknown"); 
     }
Enharmonic answered 14/3, 2016 at 0:34 Comment(1)
This need to be up voted more. Without the bitwise S_IFDIR doesn't work.Wooded
U
5

There are a set of macros to interpret st_mode, which is more complex than you think. Use them instead of probing the field directly:

if (S_ISREG(file_info.st_mode))
    // file is a regular file
else if (S_ISLNK(file_info.st_mode))
    // ...

There's also S_ISDIR, S_ISSOCK, and a few more. See, e.g., here for info.

Unveiling answered 6/10, 2011 at 12:42 Comment(0)
L
2

Mode carries lots of info.

Try the following kind of test:

if (S_ISDIR(file_info.st_mode))  puts("|| directory");
Loom answered 6/10, 2011 at 12:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.