posix_getdents — read directory entries
#include <dirent.h>
ssize_t posix_getdents(int fildes, void *buf, size_t nbyte, int flags);
The posix_getdents() function shall attempt to read directory entries from the directory associated with the open file descriptor fildes and shall place information about the directory entries and the files they refer to in posix_dent structures in the buffer pointed to by buf, up to a maximum of nbyte bytes. The number of posix_dent structures populated in buf may be fewer than the number that will fit in nbyte bytes, but shall be at least one if nbyte is greater than the size of the posix_dent structure plus {NAME_MAX} and fildes is not currently at end-of-file.
The application shall ensure that buf is aligned suitably to point to a posix_dent structure. The alignment needed shall not be more restrictive than the alignment provided by malloc(). Strictly conforming applications shall ensure that the value of flags is zero; other applications can set it to a value constructed by a bitwise-inclusive OR of implementation-defined bitwise-distinct flag values.
Each posix_dent structure returned in buf shall be located at an address that satisfies the implementation's alignment requirements for the posix_dent structure and shall be populated as follows:
The value of the d_ino member shall be set to the file serial number of the file named by the d_name member.
The value of the d_reclen member shall be set to the number of bytes occupied by this entry in buf, including any padding bytes needed before the next entry, if any. If this is the last entry in buf, d_reclen shall include any padding bytes needed to make the address of this entry plus d_reclen bytes satisfy the alignment requirements for the posix_dent structure.
The value of the d_type member shall be set to indicate the file type of the named file, if the file type can be determined without needing to use the file serial number to obtain the file's metadata; otherwise it may be set to DT_UNKNOWN. If the file type is determined and it is one of the file types defined in this standard, the value of d_type shall be DT_BLK, DT_CHR, DT_DIR, DT_FIFO, DT_LNK, DT_REG, DT_SOCK, DT_MQ, DT_SEM, DT_SHM, [TYM] or DT_TMO (see <dirent.h>). If it is determined but is not a standard file type, the value of d_type shall not equal any of those listed here.
The d_name member shall be a filename string, and (if not dot or dot-dot) shall contain the same byte sequence as the last pathname component of the string used to create the directory entry, plus the terminating NUL byte.
If the d_name member names a symbolic link, the values of the d_ino and d_type members shall be set to the values for the symbolic link itself.
The posix_getdents() function shall start reading at the current file offset in the open file description associated with fildes. On successful return, the file offset shall be incremented to point to the directory entry immediately following the last entry whose information was returned in buf, or to point to end-of-file if there are no more directory entries. On failure, the value of the file offset is unspecified. The current file offset can be set and retrieved using lseek() on the open file description associated with fildes. The behavior is unspecified if lseek() is used to set the file offset to a value other than zero or a value returned by a previous call to lseek() on the same open file description.
The posix_getdents() function shall not return directory entries containing empty names. If entries for dot or dot-dot exist, a sequence of calls that reads from offset zero to end-of-file shall return one entry for dot and one entry for dot-dot; otherwise, they shall not be returned.
Upon successful completion, posix_getdents() shall mark for update the last data access timestamp of the directory.
If fildes is a file descriptor associated with a directory stream opened using fdopendir() or opendir(), the behavior is unspecified.
If posix_getdents() is called concurrently with an operation that adds, deletes, or modifies a directory entry, the results from posix_getdents() shall reflect either all of the effects of the concurrent operation or none of them. If a sequence of calls to posix_getdents() is made that reads from offset zero to end-of-file and a file is removed from or added to the directory between the first and last of those calls, whether the sequence of calls returns an entry for that file is unspecified.
Upon successful completion, either a non-negative integer shall be returned indicating the number of bytes occupied by the posix_dent structures placed in buf or 0 shall be returned indicating the end of the directory was reached without any directory entries being placed in buf. Otherwise, -1 shall be returned and errno shall be set to indicate the error.
The posix_getdents() function shall fail if:
- [EBADF]
- The fildes argument is not a valid file descriptor open for reading.
- [EINVAL]
- The nbyte argument is not large enough to contain the information to be returned about the directory entry located at the current file offset.
- [ENOENT]
- The current file offset is not located at a valid directory entry.
- [ENOTDIR]
- The fildes argument is associated with a non-directory file.
- [EOVERFLOW]
- One of the values in a structure to be placed in buf cannot be represented correctly.
The posix_getdents() function may fail if:
- [EIO]
- A physical I/O error has occurred.
- [ENOMEM]
- Insufficient memory was available to fulfill the request.
This example function lists the files in a specified directory with their file serial number and file type. If the file type is not available from posix_getdents(), it is obtained using fstatat().
#include <dirent.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <unistd.h>
#define ENTBUFSIZ 10240
int list_dir(const char *dirnam) { int fd = open(dirnam, O_RDONLY | O_DIRECTORY); if (fd == -1) return -1;
char *buf = malloc(ENTBUFSIZ); if (buf == NULL) { close(fd); return -1; }
ssize_t bytesinbuf; for(;;) { ssize_t nextent = 0;
bytesinbuf = posix_getdents(fd, buf, ENTBUFSIZ, 0); if (bytesinbuf <= 0) break;
do { const char *ftype; struct posix_dent *entp = (void *)&buf[nextent]; if (entp->d_type == DT_UNKNOWN) { struct stat stbuf; if (fstatat(fd, entp->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == -1) ftype = "?"; else ftype = S_ISBLK(stbuf.st_mode) ? "b" : S_ISCHR(stbuf.st_mode) ? "c" : S_ISDIR(stbuf.st_mode) ? "d" : S_ISFIFO(stbuf.st_mode) ? "p" : S_ISLNK(stbuf.st_mode) ? "l" : S_ISREG(stbuf.st_mode) ? "r" : S_ISSOCK(stbuf.st_mode) ? "s" : S_TYPEISMQ(&stbuf) ? "mq" : S_TYPEISSEM(&stbuf) ? "sem" : S_TYPEISSHM(&stbuf) ? "shm" : #ifdef S_TYPEISTMO S_TYPEISTMO(&stbuf) ? "tmo" : #endif "?"; } else { ftype = entp->d_type == DT_BLK ? "b" : entp->d_type == DT_CHR ? "c" : entp->d_type == DT_DIR ? "d" : entp->d_type == DT_FIFO ? "p" : entp->d_type == DT_LNK ? "l" : entp->d_type == DT_REG ? "r" : entp->d_type == DT_SOCK ? "s" : entp->d_type == DT_MQ ? "mq" : entp->d_type == DT_SEM ? "sem" : entp->d_type == DT_SHM ? "shm" : #ifdef DT_TMO entp->d_type == DT_TMO ? "tmo" : #endif "?"; }
printf("%ld\t%s\t%s\n", (long)entp->d_ino, ftype, entp->d_name);
nextent += entp->d_reclen;
} while (nextent < bytesinbuf); }
close(fd); free(buf); return bytesinbuf; }
If an array of posix_dent structures (which is only possible on implementations where d_name is not a flexible array member) is used to provide the storage for buf in order to satisfy the alignment requirement, it should be noted that the number of array elements used to size the array may bear little or no relation to the number of directory entries that can be stored in it. It is recommended that the number of elements is calculated from the desired size in bytes, for example:
#define DESIREDSIZE 10240 struct posix_dent buf[DESIREDSIZE / sizeof(struct posix_dent) + 1]; size_t nbyte = sizeof buf;When posix_getdents() is called with a buf that is not type char *, it is important to note that d_reclen is a byte count and therefore any pointer arithmetic involved in calculating the start of the next entry needs to use a char * pointer.
On implementations where directory entries in a directory take up more space than the corresponding posix_dent structures in buf, a call to posix_getdents() may read nbyte bytes from the directory, resulting (in most cases) in the actual number of bytes placed in buf being less than nbyte.
One advantage of posix_getdents() is that it provides the file type of each directory entry (if available), whereas readdir() only does so on implementations that have the file type as a non-standard additional member of the dirent structure. Knowing the file type can greatly reduce the number of fstatat() calls that need to be made when traversing the file hierarchy.
Whether or not a file's type can be determined without needing to use the file serial number to obtain the file's metadata may vary across the different file system types supported by an implementation. Therefore applications should not assume that if d_type contains known file types (i.e. not DT_UNKNOWN) for entries in a given directory then it will also contain known file types for entries in subdirectories of that directory or in its parent.
Since the d_reclen value for the last entry in buf includes padding to satisfy alignment requirements, applications can grow the buffer and call posix_getdents() again to append to it without needing to perform an alignment calculation.
The posix_getdents() function was derived from existing getdents() functions but the name was changed because the existing getdents() functions differed in various ways, in particular the type of the second argument (structure pointer or void *), the members of the populated structures, and the error numbers used for some conditions. The name change also provided an opportunity to add a flags argument to provide for future extensibility.
Implementations are encouraged to include support for a DT_FORCE_TYPE flag which, when that bit is set in flags, causes posix_getdents() to look up the file type if it can not be obtained from the directory entry. This will allow applications that need to know the file type of every directory entry to keep the cost of these lookups to the minimum needed to obtain the type at the file system level, without the additional overhead of making a call to fstatat() for every file (that has d_type equal to DT_UNKNOWN).
Some existing getdents() or similar functions return directory entry structures for deleted directory entries in buf, marked with a special value of one of the structure members to distinguish them from non-deleted entries. This behavior is not allowed for posix_getdents(), although the data from a deleted directory entry may be present in buf in the form of extra padding on the end of the previous entry.
A future version of this standard may add a DT_FORCE_TYPE flag as described in RATIONALE.
fdopendir, fstatat, lseek, readdir
XBD <dirent.h>
First released in Issue 8.
return to top of page