Search code examples
clinuxunixfilesystemstraversal

Traversing a Filesystem with fts(3)


I have a question on fts(3). I am getting a segmentation fault whenever I try to access any members of the fts_children() function. When I read the man page at http://www.kernel.org/doc/man-pages/online/pages/man3/fts.3.html it claims to fill itself after the read function runs and returns a linked list linked through the link field in the structure. My suspicion is that the child_function is returning nothing but I feel like that doesn't line up with the man page. Am I supposed to be adding these files to the child buffer because I thought that was being done automatically? My code is below, Thanks!

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fts.h>
#include<string.h>

int compare (const FTSENT**, const FTSENT**);

int main(int argc, char* const argv[])
{

        FTS* file_system = NULL;
        FTSENT* child = NULL;
        FTSENT* parent = NULL;
        FTSENT* temp = NULL;

        file_system = fts_open(argv + 1,FTS_COMFOLLOW | FTS_NOCHDIR,&compare);

        while( (parent = fts_read(file_system)) != NULL)
        {

             child = fts_children(file_system,0);
             printf("%s\n", child->fts_path);


        }
//      while (child ->fts_link != NULL)
      //         child = child->fts_link;
        fts_close(file_system);
        return 0;
}

int compare(const FTSENT** one, const FTSENT** two){
        return (strcmp((*one)->fts_name, (*two)->fts_name));
}
"test_fs.c" 43L, 1108C  

Solution

  • You simply need to add a NULL check.

    You might want to

    • add one for file_system
    • check for command line arguments
    • Add more errorhandling:

      The fts_children() function returns a pointer to an FTSENT structure describing the first entry in a NULL terminated linked list of files in the directory, if successful. The fts_children() function may fail and set errno for any of the errors that the chdir(), malloc(), opendir(), readdir(), and stat() functions specify.

    Update To the new question(s) in the comment:

    • The while loop for linked list traversal was misplaced (outside the outer loop?)
    • The printf displayed only the path... not the filename.

    while you're at it:

    #include<stdlib.h>
    #include<stdio.h>
    #include<sys/types.h>
    #include<sys/stat.h>
    #include<fts.h>
    #include<string.h>
    #include<errno.h>
    
    int compare (const FTSENT**, const FTSENT**);
    
    int main(int argc, char* const argv[])
    {
        FTS* file_system = NULL;
        FTSENT* child = NULL;
        FTSENT* parent = NULL;
    
        if (argc<2)
        {
            printf("Usage: %s <path-spec>\n", argv[0]);
            exit(255);
        }
    
        file_system = fts_open(argv + 1,FTS_COMFOLLOW | FTS_NOCHDIR,&compare);
    
        if (NULL != file_system)
        {
            while( (parent = fts_read(file_system)) != NULL)
            {
                child = fts_children(file_system,0);
    
                if (errno != 0)
                {
                    perror("fts_children");
                }
    
                while ((NULL != child)
                    && (NULL != child->fts_link))
                {
                    child = child->fts_link;
                    printf("%s%s\n", child->fts_path, child->fts_name);
                }
            }
            fts_close(file_system);
        }
        return 0;
    }
    
    int compare(const FTSENT** one, const FTSENT** two)
    {
        return (strcmp((*one)->fts_name, (*two)->fts_name));
    }
    

    Sample output fragment:

    ./.profiles/sehe/.opera/icons/cache/g_0000
    ./.profiles/sehe/.opera/icons/cache/g_0000/opr00002.tmp
    ./.profiles/sehe/.opera/icons/cache/g_0000/opr00003.tmp
    ./.profiles/sehe/home/sehe/.mozilla
    fts_children: Permission denied
    ./.vbox-sehe-ipc/lock