Traversing a Filesystem with fts(3) Traversing a Filesystem with fts(3) unix unix

Traversing a Filesystem with fts(3)


If you are only interested in traversing all directories and files for the specified path(s), just repeatedly call fts_read.

If you want to only iterate through the stream, @sehe's example could be rewritten as:

#include<stdlib.h>#include<stdio.h>#include<sys/types.h>#include<fts.h>#include<string.h>#include<errno.h>int compare (const FTSENT**, const FTSENT**);void indent (int i);int main(int argc, char* const argv[]){    FTS* file_system = NULL;    FTSENT *node,    = 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( (node = fts_read(file_system)) != NULL)        {            switch (node->fts_info)             {                case FTS_D :                case FTS_F :                case FTS_SL:                    indent(node->fts_level);                    printf("%s\n", node->fts_name);                    break;                default:                    break;            }        }        fts_close(file_system);    }    return 0;}int compare(const FTSENT** one, const FTSENT** two){    return (strcmp((*one)->fts_name, (*two)->fts_name));}void indent(int i){    for (; i > 0; i--)         printf("    ");}

When you run it, it iterates through the stream and lists all files and directories in order:

★ mkdir -p test/A/1 test/A/2 test/B/1 test/B/2★ tree test                                   test├── A│   ├── 1│   └── 2└── B    ├── 1    └── 2★ ./fts test                                  test    A        1        2    B        1        2

Call fts_children only if you want a list of child nodes of a specific directory. In that case you must call fts_read at least once before calling fts_children; otherwise fts_children will only return nodes specified in argv parameter to fts_open.


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/.mozillafts_children: Permission denied./.vbox-sehe-ipc/lock