NAME
posix_getdents —
read directory entries
SYNOPSIS
#include
<dirent.h>
ssize_t posix_getdents(int fildes, void *buf, size_t nbyte, int flags);
DESCRIPTION
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(3). 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(3) on the open file description
associated with fildes. The behavior is unspecified if
lseek(3) is used to set the file offset to a value other
than zero or a value returned by a previous call to
lseek(3) 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(3) or opendir(3), 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.
RETURN VALUE
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.
ERRORS
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:
EXAMPLES
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(3).
#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;
}
APPLICATION USAGE
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(3)
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(3) 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.
RATIONALE
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(3) 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.
FUTURE DIRECTIONS
A future version of this standard may add a DT_FORCE_TYPE flag as described in RATIONALE.
SEE ALSO
fdopendir(3), fstatat(3), lseek(3), readdir(3)
XBD <dirent.h>
CHANGE HISTORY
First released in Issue 8.