DIRECTORY(3)
๐ DIRECTORY(3) ๐
ok so like โ welcome to the directory-ops page bestie!! this is from the Library Functions Manual (that's the man page section, iykyk) and honestly? it's giving "everything you need to know about opening, reading and closing directories" and i'm obsessed ๐
โจ NAME โจ
opendir, fdopendir, readdir, readdir_r, telldir, seekdir, rewinddir, closedir, fdclosedir, dirfd โ directory operations ๐
๐ LIBRARY ๐
Standard C Library (libc, -lc) ๐ธ
๐ซ SYNOPSIS ๐ซ
#include <dirent.h>
DIR *
opendir(const char *filename);
DIR *
fdopendir(int fd);
struct dirent *
readdir(DIR *dirp);
int
readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
long
telldir(DIR *dirp);
void
seekdir(DIR *dirp, long loc);
void
rewinddir(DIR *dirp);
int
closedir(DIR *dirp);
int
fdclosedir(DIR *dirp);
int
dirfd(DIR *dirp);
๐ฆ DESCRIPTION ๐ฆ
so first things first, the callout: readdir_r() is deprecated ๐ญ and the reason is lowkey iconic โ you literally cannot use it correctly unless {NAME_MAX} is a fixed value. like, it's just not it anymore, bestie.
opendir() opens up the directory named by filename, associates a directory stream with it, and hands you back a pointer. that pointer is your new bestie for identifying the directory stream in all the operations that come after ๐
fdopendir() is literally opendir() but make it descriptor-flavored โจ โ same thing, except the directory is specified by a file descriptor fd instead of a name. and ngl, the file offset that's chillin' on the file descriptor at the time of the call decides which entries get returned.
๐จ ok this part is important so pay attention: oncefdopendir()returns successfully, the file descriptor is under the control of the system. if you try to close it, or change the state of the associated description in any way other than viaclosedir(),readdir(),readdir_r(), orrewinddir()โ that's undefined behavior. not "kinda weird behavior", UNDEFINED. don't do it ๐
when you call closedir(), the file descriptor gets closed. and hey, a successful fdopendir() call sets the FD_CLOEXEC flag on the file descriptor ๐
readdir() returns a pointer to the next directory entry ๐ฏ heads up though: that entry stays valid only until the next call to readdir() or closedir() on the same directory stream. so don't get attached, it's not sticking around ๐
readdir_r() does the same thing as readdir(), except you have to hand it a directory entry buffer to stash the results in. that buffer has to be big enough for a struct dirent with a d_name array of {NAME_MAX} + 1 elements. if the read succeeds, result points at the entry; when you hit the end of the directory, result gets set to NULL. (and yes, we already established it's deprecated, i'm just being thorough ๐ซถ)
telldir() gives you back a token representing the current location associated with the named directory stream. but like... these tokens are only good for the lifetime of the directory stream they came from ๐ if the directory gets closed and then reopened, all your old telldir() values are no longer valid. and a call to rewinddir() also invalidates values returned by telldir(). so sad, so tragic ๐
seekdir() sets the position for the next readdir() operation on the directory stream. the new position reverts to the one that was associated with the directory stream back when the telldir() operation was performed. it's giving "time travel but only for directory offsets" โญ
rewinddir() resets the position of the named directory stream back to the beginning of the directory. fresh start energy ๐
closedir() closes the named directory stream and frees the structure associated with dirp. bye bestie ๐
fdclosedir() is the same as closedir() except instead of closing it, it returns the file descriptor associated with dirp. iconic behavior honestly ๐
dirfd() returns the file descriptor associated with dirp. that's the whole function. short king ๐ซถ
๐ฅ EXAMPLES ๐ฅ
here's sample code that searches a directory for the entry ``name'' โ look at it, learn it, love it:
dirp = opendir(".");
if (dirp == NULL)
return (ERROR);
len = strlen(name);
while ((dp = readdir(dirp)) != NULL) {
if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) {
(void)closedir(dirp);
return (FOUND);
}
}
(void)closedir(dirp);
return (NOT_FOUND);
๐ RETURN VALUES ๐
opendir()andfdopendir()โ return a pointer to the new directory stream on success ๐ andNULLon failure ๐ญreaddir()โ returns a pointer to a directory entry on success,NULLon failure.readdir_r()returns0on success and an error number on failure.telldir()โ returns a nonnegative value on success and-1on failure.closedir()โ returns0on success and-1on failure. bothfdclosedir()anddirfd()return an open file descriptor on success and-1on failure.
๐จ ERRORS ๐จ
opendir() will fail if:
[EACCES]โ search permission is denied for the component of the path prefix offilename, or read permission is denied forfilename๐[ELOOP]โ there's a loop in symbolic links encountered during resolution of thefilenameargument ๐[ENAMETOOLONG]โ the length of thefilenameargument exceeds{PATH_MAX}, or a pathname component is longer than{NAME_MAX}๐[ENOENT]โ a component offilenamedoesn't name an existing directory, orfilenameis an empty string ๐ซฅ[ENOTDIR]โ a component offilenameis not a directory. rude.
fdopendir() will fail if:
[EBADF]โ thefdargument is not a valid file descriptor open for reading ๐[ENOTDIR]โ the descriptorfdis not associated with a directory.
the rest of the squad
readdir() and readdir_r() may also fail and set errno for any of the errors specified for the routine getdents(2).
telldir() may also fail and set errno for any of the errors specified for the routine realloc(3).
closedir() may also fail and set errno for any of the errors specified for the routine close(2).
dirfd() will fail if:
[EINVAL]โ thedirpargument does not refer to a valid directory stream ๐ซ
๐ซถ SEE ALSO ๐ซถ
close(2), lseek(2), open(2), read(2), dir(5) โ go read those next, i'll wait ๐
๐ STANDARDS ๐
closedir(), dirfd(), fdopendir(), opendir(), readdir(), readdir_r(), rewinddir(), seekdir() and telldir() are all expected to conform to IEEE Std 1003.1-2008 (โPOSIX.1โ) โจ slay.
but listen โ fdclosedir() and the d_off, d_reclen and d_type fields of struct dirent are non-standard, and should not be used in portable programs ๐ฉ like, they're the "don't take this out of the house" of the directory world.
๐ธ HISTORY ๐ธ
opendir(), readdir(), telldir(), seekdir(), rewinddir(), closedir(), and dirfd() all appeared in 4.2BSD โ ancient queens ๐โจ then fdopendir() showed up in FreeBSD 8.0, and the fdclosedir() function appeared in FreeBSD 10.0. glow-ups all around ngl ๐
๐ BUGS ๐
ok so the behavior of telldir() and seekdir() is likely to be wrong if there are parallel unlinks happening and the directory is larger than one page ๐ญ like, genuinely, it's a mess.
there is code to ensure that a seekdir() to the location given by a telldir() immediately before the last readdir() will always set the correct location to return the same value as that last readdir() performed. that's enough for some applications that want to "push back the last entry read", e.g., Samba ๐ซถ
but seeks back to any other location, other than the beginning of the directory, may result in unexpected behavior if deletes are present ๐ it is hoped that this situation will be resolved with changes to getdirentries() and the VFS ๐ค
and that's the page bestie!! ๐ this beauty comes to you from Debian, dated January 31, 2026 โ go forth and open some directories, and pls don't violate the fdopendir() rules, i'm begging ๐ฅบ๐โจ
๐ฆ where this page comes from
- freebsd 15.1: base 15.1
- Copyright (c) 1983, 1991, 1993 The Regents of the University of California. All rights reserved
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms