readdir(), readdir64()

Updated: April 19, 2023

Read a directory entry

Synopsis:

#include <dirent.h>

struct dirent *readdir( DIR *dirp );

struct dirent64 *readdir64( DIR *dirp );

Arguments:

dirp
A pointer to the directory stream to be read.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The readdir() and readdir64() functions read the next directory entry from the directory specified by dirp, which is the value returned by a call to opendir(). The readdir64() function is a large-file support version of readdir().

Note:
  • In QNX Neutrino 6.6 or later, the large-file support functions and data types appear in the name space only if you define _LARGEFILE64_SOURCE when you compile your code. For more information, see Classification in What's in a Function Description?
  • The ftw() function provides another way to walk a file tree.

You can call readdir() repeatedly to list all of the entries contained in the directory specified by the pathname given to opendir(). You must call closedir() to close the directory stream and free the memory allocated by opendir().

The <dirent.h> file defines the dirent and dirent64 structures, and the DIR type used by the readdir() family of functions.

Note: The result of using a directory stream after one of the exec*() or spawn*() family of functions is undefined. After a call to fork(), either the parent or the child (but not both) can continue processing the directory stream, using the readdir() and rewinddir() functions. If both the parent and child processes use these functions, the result is undefined. Either (or both) processes may use closedir().

The <dirent.h> file also defines the following macros for accessing extra data associated with the dirent and dirent64 structures:

_DEXTRA_FIRST( pdirent )
Get a pointer to the first block of data associated with the structure pointed to by pdirent.
_DEXTRA_NEXT( last)
Get the block of data that follows the block pointed to by last.
_DEXTRA_VALID( extra, pdirent)
Evaluates to 1 if extra is a pointer to a valid block of data associated with the structure pointed to by pdirent.

The blocks of data are dirent_extra or dirent_extra_stat structures:

struct dirent_extra {
    uint16_t            d_datalen;      /* data size (without header) */
    uint16_t            d_type;
    uint32_t            d_reserved;
    /* unsigned char    d_data[d_datalen] */
};

struct dirent_extra_stat {
    uint16_t            d_datalen;      /* sizeof(struct stat) */
    uint16_t            d_type;
    uint32_t            d_reserved;
    struct stat         d_stat;
};

The d_type member identifies the type of extra information. Its value is from the dirent_extra_type enumerated type, and it depends on whether you're using a 32- or 64-bit architecture, and on the version of POSIX (see the entry for struct stat).

enum dirent_extra_type {
        _DTYPE_NONE,
        _DTYPE_STAT_UNSET,
        _DTYPE_LSTAT_UNSET,
        _DTYPE_STAT_T32_2001,
        _DTYPE_LSTAT_T32_2001,
        _DTYPE_STAT_T32_2008,
        _DTYPE_LSTAT_T32_2008,
        _DTYPE_STAT_T64_2008,
        _DTYPE_LSTAT_T64_2008,
#if __PTR_BITS__ == 32
        _DTYPE_STAT = _DTYPE_STAT_T32_2001,
        _DTYPE_LSTAT = _DTYPE_LSTAT_T32_2001,
#else
        _DTYPE_STAT = _DTYPE_STAT_T64_2008,
        _DTYPE_LSTAT = _DTYPE_LSTAT_T64_2008,
#endif
};

You can use these macros to traverse the data associated with the dirent structure like this:

for( extra = _DEXTRA_FIRST(dirent); 
    _DEXTRA_VALID(extra, dirent); 
    extra = _DEXTRA_NEXT(extra)) {
      switch(extra->d_type) {

         case _DTYPE_NONE  : 
            /* No data */
            break;

         case _DTYPE_STAT  :
            /* Data includes information as returned by stat() */
            break;

         case _DTYPE_LSTAT : 
            /* Data includes information as returned by lstat() */
            break;
         …
     }
}

If the value of the d_type member is _DTYPE_STAT or _DTYPE_LSTAT, the d_stat member is a struct stat. You can use the dircntl() function to request that the filesystem include this extra information.

Returns:

A pointer to a struct dirent or struct dirent64 object for success, or NULL if the end of the directory stream is encountered or an error occurs (errno is set).

Note:
  • A returned value of NULL is ambiguous; if you need to determine if it indicates an error (as opposed to the end of the directory stream), set errno to EOK before each call to this function.
  • Although dirent and dirent64 are declared with a one-byte d_name field, the structure that readdir() and readdir64() returns is allocated with enough space to hold the entire name.
  • Subsequent calls to readdir() or readdir64() with the same directory stream may overwrite the memory that the returned pointer points to, but such calls don't affect the memory returned for calls to these functions for other directory streams.

Errors:

EOVERFLOW
One of the values in the structure to be returned can't be represented correctly.

Examples:

Get a list of files contained in the directory /home/fred:

#include <stdio.h>
#include <dirent.h>
#include <stdlib.h>

int main( void )
{
    DIR* dirp;
    struct dirent* direntp;

    dirp = opendir( "/home/fred" );
    if( dirp != NULL ) {
        for(;;) {
            direntp = readdir( dirp );
            if( direntp == NULL ) break;

            printf( "%s\n", direntp->d_name );
        }

        closedir( dirp );
        
        return EXIT_SUCCESS;
    }

    return EXIT_FAILURE;
}

Get stat data while reading a directory:

/*
 * This function gets stat information from the dirent.
 * If it isn't supported (ramdisk, symlinks, etc.), we fall back to
 * a generic stat and return that instead.
 *
 * @returns     0 on success (statp structure populated);
 * @returns    -1 on error;
 */
static int sync_stat( const char *path, struct dirent *ent, struct stat *statp ) {
    struct dirent_extra        *dex;
    struct dirent_extra_stat    *dex_stat;

    // Get the dirent stat
    for ( dex = _DEXTRA_FIRST(ent); _DEXTRA_VALID(dex, ent);
         dex = _DEXTRA_NEXT(dex) ) {
        if ( dex->d_type == _DTYPE_STAT || dex->d_type == _DTYPE_LSTAT ) {
            dex_stat = (struct dirent_extra_stat *) dex;
            memcpy( statp, &(dex_stat->d_stat), sizeof(struct stat) );
            return 0;
        }
    }

    // We failed the dirent stat.  Return the normal one.
    return stat(path, statp);
}



// The volume label should be a name-special file at the root folder.
// Depending on the way fs-dos is used, that name special file will be prefixed
// by an '=' character which will need to be stripped off.
dir = opendir( mountpath );
if ( dir == NULL ) {
    log_error( 1, "Could not open %s to find the volume name\n", mountpath );
    return -1;
}
// Turn on stat info in the dirent.
if ( (dirflags = dircntl(dir, D_GETFLAG)) == -1 ) {
    log_error( 1, "Could not request stat information for dir %s. (%s)\n",
                            mountpath, strerror(errno) );
}
else if (dircntl(dir, D_SETFLAG, dirflags | D_FLAG_STAT) == -1) {
    log_error( 1, "Could not request stat information for dir %s. (%s)\n",
                            mountpath, strerror(errno));
}
while ((ent = readdir(dir))) {
    strcpy( statpath, mountpath );
    strcat( statpath, "/" );
    strcat( statpath, ent->d_name );

    if ( sync_stat(statpath, ent, &buf) == 0 ) {
        Do something with the data.
    }
    else {
        log_error( 1, "Could not stat %s. (%s)\n", statpath, strerror(errno) );
    }
}
log_error( 1, "Could not find volume name in %s\n", mountpath );
closedir(dir);

Classification:

readdir() is POSIX 1003.1; readdir64() is Large-file support

Safety:  
Cancellation point Yes
Interrupt handler No
Signal handler No
Thread No