DIRECTORY(3)

๐Ÿ“ฆ
version 15.1 ยท 2 versions
, in freebsd 15.1

๐ŸŽ€ 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: once fdopendir() 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 via closedir(), readdir(), readdir_r(), or rewinddir() โ€” 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() and fdopendir() โ€” return a pointer to the new directory stream on success ๐Ÿ’– and NULL on failure ๐Ÿ˜ญ
  • readdir() โ€” returns a pointer to a directory entry on success, NULL on failure. readdir_r() returns 0 on success and an error number on failure.
  • telldir() โ€” returns a nonnegative value on success and -1 on failure.
  • closedir() โ€” returns 0 on success and -1 on failure. both fdclosedir() and dirfd() return an open file descriptor on success and -1 on failure.

๐Ÿšจ ERRORS ๐Ÿšจ

opendir() will fail if:

  • [EACCES] โ€” search permission is denied for the component of the path prefix of filename, or read permission is denied for filename ๐Ÿ™ˆ
  • [ELOOP] โ€” there's a loop in symbolic links encountered during resolution of the filename argument ๐ŸŒ€
  • [ENAMETOOLONG] โ€” the length of the filename argument exceeds {PATH_MAX}, or a pathname component is longer than {NAME_MAX} ๐Ÿ“
  • [ENOENT] โ€” a component of filename doesn't name an existing directory, or filename is an empty string ๐Ÿซฅ
  • [ENOTDIR] โ€” a component of filename is not a directory. rude.

fdopendir() will fail if:

  • [EBADF] โ€” the fd argument is not a valid file descriptor open for reading ๐Ÿ’€
  • [ENOTDIR] โ€” the descriptor fd is 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] โ€” the dirp argument 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
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms