clinuxdirectorystatreaddir

Differentiating between files and directories on linux in C


I have a function that takes in an argument which is a file path. That path is then used in conjunction with the readdir function and stat function to print out all of the files and directories in a directory. The issue I have is when I try to sort the files and directories, they are all viewed as directories. I have looked at similar examples on here and I believe the issue is the way I have stat formatted. I just don't understand how stat works and I have even looked at the manual pages but they are not making a lot of sense.

Here is my code:

void scan(const char *dir) {
    DIR *directory;
    struct dirent *file;
    struct stat info;

    directory = opendir(dir);

    if (directory == NULL) {
        printf("Cannot open directory: %s\n", dir);
        return;
    }
    while ((file = readdir(directory)) != NULL) {
        if (file->d_name[0] == '.') {
            // then hidden file, so leave hidden
            continue;
        }
        
        if (stat(dir, &info) == -1) {
            printf("can't find %s\n", file->d_name);
            perror("ERROR");
        }

        // determine if file or directory
        if (S_ISREG(info.st_mode))
            printf("File: ");
        if (S_ISDIR(info.st_mode))
            printf("Dir: ");

        // display the name of the file
        printf("%s\n", file->d_name);
    }
    closedir(directory);
}

Here is the output that I keep getting...

Dir: par_hash_table.c
Dir: BlackBoxTesting
Dir: Makefile
Dir: in3.txt
Dir: par_hash_table.o
Dir: in5.txt
Dir: par_hash_table
Dir: in4.txt
Dir: in6.txt
Dir: in1.txt
Dir: in2.txt
Dir: in8.txt
Dir: in7.txt

Here is the command I am using, I'm using Linux and the file path doesn't need to be this particular but I just wanted to show everything...

./par_hash_table 1 2 /home/dpb/Documents/CSE_420/P3

Any help figuring out how I can differentiate a txt file from a folder would help.


Solution

  • Your error is here:

        if(stat(dir, &info) == -1){
            printf("can't find %s\n", file->d_name);
            perror("ERROR");
           }
    

    You are getting stat for the function parameter dir every time. You want to stat the file from the directory entry, instead. So you need to concatenate the dir and the file names, to get full path for stat.


    Code to concat the parts:

    char filepath[strlen(dir) + 1 + strlen(file->d_name) + 1];
    snprintf(filepath, sizeof filepath, "%s/%s", dir, file->d_name);
    if(stat(filepath, &info) == -1){
       ....
    

    (A side note, incidentally this is one of the very few cases where I think using a VLA is fine. Just be careful if you convert this to a recursive function, make sure the VLA goes out of scope before the recursive call... Or just use malloc and free to be safe from stack overflow.)


    Also, please run your code through auto-formater, which also can add the missing optional {}. It really is quite a good idea to use {} for every block, even if it is just one statement. Or, if you don't find a C auto-formatter, your editor should at least have auto-indentation, so add the {} yourself and then auto-indent the code.