Search code examples
crecursionls

Recursive listing


I've been having problems trying to implement something like ls -R on C, The thing is that I need list recursively list everything starting from a given directory and then do stuff with those regular files I get from the list. This is what I have so far:

 void ls(char* path){
    DIR *directory;
    struct dirent *filei;
    struct stat stats;
    directory = opendir(path);
    if (directory != NULL)  
    {
        while ((filei=readdir(directory))!=NULL){
            stat(filei->d_name, &stats);    
            printf(" %s\n", filei->d_name); 
            if (S_ISDIR(stats.st_mode)){
                char *buf = malloc(strlen(path)+strlen(filei->d_name)+2);
                strcpy(buf,path);
                strcat(buf,"/");
                strcat(buf,filei->d_name);
                ls(buf);
            }
        }
        closedir(directory);
    }
    else{
        printf("Error.\n");     
    }
}

It doesn't work at all, it shows files that are not even in the folder I'm working with. Any thoughts? Thanks.


Solution

  • The following rework of your code calls stat() on the full file path, skips over the "." and ".." directories, fixes the memory leak and adds just a touch of error handling:

    #define SEPARATOR "/"
    
    void ls(const char *path)
    {
        DIR *directory = opendir(path);
    
        if (directory != NULL)  
        {
            struct dirent *filei;
    
            while ((filei = readdir(directory)) != NULL)
            {
                if (strcmp(filei->d_name, ".") == 0 || strcmp(filei->d_name, "..") == 0)
                {
                    continue;
                }
    
                char *buffer = malloc(strlen(path) + strlen(filei->d_name) + strlen(SEPARATOR) + 1);
                strcat(strcat(strcpy(buffer, path), SEPARATOR), filei->d_name);
    
                struct stat stat_buffer;
    
                if (stat(buffer, &stat_buffer) == 0)
                {   
                    printf("%s\n", buffer); 
    
                    if (S_ISDIR(stat_buffer.st_mode))
                    {
                        ls(buffer);
                    }
                }
                else
                {
                    perror(NULL);
                }
    
                free(buffer);
            }
    
            closedir(directory);
        }
        else
        {
            perror(NULL);     
        }
    }
    

    See if it works any better for you.