Search code examples
cdirectorystatreaddir

stat using S_ISDIR Don't seem to always work


I've noticed something strange in the output of my function (in c). This function detect in a directory if an element is a file or a subdirectory.

// i cant detected properly if an element is a file or a dir 
int RecursiveSearch(char *Dir){
    DIR *Directory;
    //DIR *SubDirectory;
    struct dirent *entry;
    struct stat filestat;

    printf("I am Reading %s Directory\n", Dir);

    Directory = opendir(Dir);
    if(Directory == NULL)
    {
        perror("Unable to read directory.. i'm leaving\n");
        return(1); // leave
    }

    /* Read directory entries */
    while( (entry=readdir(Directory)) )
    {
        stat(entry->d_name,&filestat);
        if( S_ISDIR(filestat.st_mode) ){
            printf("%4s: %s\n","Dir",entry->d_name);
            if (strstr(entry->d_name, ".") == NULL && strstr(entry->d_name, "..") == NULL ) // to not infinit loop
            {
                // Recursion
                printf("\n*Entering a subDirectory*\n");
                RecursiveSearch(entry->d_name);
                printf("\n*Leaving a subDirectory*\n");
            }


        }
        else
            printf("%4s: %s\n","File",entry->d_name);
    }
    closedir(Directory);

    return(0);
}

I call it in the main like this to test it RecursiveSearch("./Directories");

And this is my outputenter image description here

My problem is under "Starting Recursive Research.."

As you can see SubDir is not a file. I can't see what i did wrong in the function.

If you need any additional clarification please ask.

EDIT :

int RecursiveSearch(char *Dir){
    DIR *Directory;
    struct dirent *entry;
    struct stat filestat;

    printf("I am Reading %s Directory\n", Dir);

    Directory = opendir(Dir);
    if(Directory == NULL)
    {
        perror("Unable to read directory.. i'm leaving\n");
        return(1); // leave
    }

    /* Read directory entries */
    while( (entry=readdir(Directory)) )
    {
        char fullname[100];
        sprintf(fullname, "%s/%s",Dir,entry->d_name);
        stat(fullname,&filestat);
        if( S_ISDIR(filestat.st_mode) ){
            printf("%4s: %s\n","Dir",fullname);
            if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 ) // to not infinite loop
            {
                // Recursion
                printf("\n*Entering a subDirectory*\n");
                RecursiveSearch(fullname);
                printf("\n*Leaving a subDirectory*\n");
            }
        }
        else
            printf("%4s: %s\n","File",fullname);
    }
    closedir(Directory);

    return(0);
}

Solution

  • entry->d_name is just the name, it doesn't have the directory prefix. It's interpreted relative to the process's working directory, not the current directory in the recursion of the function.

    You need to prefix the name with the directory name when calling other functions, including the recursion.

    Also, you need to use strcmp() to compare the name to . and ... Using strstr() prevents recursing into directories that have . anywhere in the names.

    int RecursiveSearch(char *Dir){
        DIR *Directory;
        struct dirent *entry;
        struct stat filestat;
    
        printf("I am Reading %s Directory\n", Dir);
    
        Directory = opendir(Dir);
        if(Directory == NULL)
        {
            perror("Unable to read directory.. i'm leaving\n");
            return(1); // leave
        }
    
        /* Read directory entries */
        while( (entry=readdir(Directory)) )
        {
            char fullname[MAXPATH];
            sprintf(fullname, "%s/%s", Dir, entry->d_name);
            stat(fullname,&filestat);
            if( S_ISDIR(filestat.st_mode) ){
                printf("%4s: %s\n","Dir",fullname);
                if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0 ) // to not infinite loop
                {
                    // Recursion
                    printf("\n*Entering a subDirectory*\n");
                    RecursiveSearch(fullname);
                    printf("\n*Leaving a subDirectory*\n");
                }
            }
            else
                printf("%4s: %s\n","File",fullname);
        }
        closedir(Directory);
    
        return(0);
    }