Search code examples
cstat

Why does stat return wrong result?


I want to check whether given arguments are directory or not by using stat. The program takes 2 argument: when first arguments is not directory or it does not exist code works correctly.

But when first argument is a directory and exists, and the second argument does not exist, the program says both of them exist -- wrong result. I would like to know why it does not work.

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


int main(int n, char **argv)
{
    char *dir_1=argv[1], *dir_2=argv[2];


    if (is_dir(dir_1) == 0)
            printf("Directory %s exists.\n", dir_1);
    else
            printf("Directory %s does not exist.\n", dir_1);

    if (is_dir(dir_2) == 0)
            printf("Directory  %s exists.\n", dir_2);
    else
            printf("Directory  %s does not exist.\n", dir_2);

}


int is_dir(char *file)
{
        struct stat file_stat;
        stat(file, &file_stat);
        return( (S_ISDIR(file_stat.st_mode)) ? 0 : -1);
}

Solution

  • If the file does not exist, stat itself returns -1, and sets errno to ENOENT. But since the first directory existed and was a directory, the struct stat was filled with the information of a directory; this happens to be located at the exact same location in the stack for the second stat invocation. The second stat failed with the errno ENOENT, but then is_dir interpreted the values left by the first invocation.


    More correct implementation for the is_dir could be:

    int is_dir(char *file)
    {
        struct stat file_stat;
    
        // if an error occurs, we return 0 for false
        if (stat(file, &file_stat) < 0) {
            return 0;
        }
    
        // otherwise we return whatever the S_ISDIR returns
        return S_ISDIR(file_stat.st_mode);
    }
    

    Notice that I change the return value too; a function such as is_dir is expected to return a boolean value that is truish (non-zero) in the case of the function name stating a true fact, zero otherwise.

    You'd use it like:

    if (is_dir(dir_1)) {
            printf("Directory %s exists.\n", dir_1);
    }
    else {
            printf("Directory %s does not exist.\n", dir_1);
    }
    
    if (is_dir(dir_2)) {
            printf("Directory  %s exists.\n", dir_2);
    }
    else {
            printf("Directory  %s does not exist.\n", dir_2);
    }
    

    Note that the return value 0 in this case does not mean that there necessarily is no directory with that name; the stat system call could fail also because of insufficient permissions and so on; extending the logic (interpreting the value of errno) is beyond the scope of this answer.