#ifndef VLIBC_DIRENT_H #define VLIBC_DIRENT_H /* * vlibc — . * * Directory streams: opendir/fdopendir/readdir/rewinddir/closedir, * seekdir/telldir/dirfd (POSIX.1-2008 base) iterate a directory via the * SYS_getdents64 kernel ABI, exposing one entry at a time. * * Level 1 (onlyposix): the base family above. * Level 2 (muslmimic): scandir, alphasort (XSI) and readdir_r * (obsolescent). versionsort is GNU and is not * provided. * * struct dirent mirrors the x86_64 getdents64 record layout (verified by * the static assertions below): d_ino/d_off are 64-bit, d_reclen is the * kernel record length, d_type carries the DT_* file type, and d_name is a * 256-byte NUL-terminated name buffer (NAME_MAX 255 + NUL). * * DIR is an opaque handle whose layout lives in the internal header * src/dirent/dirent_impl.h. None of these declarations carries an intent * attribute: every function performs I/O with side effects and reports * failures through errno, so const/pure would be unsound (the same * rationale sys/stat.h documents for its I/O family). */ #include #include #include #ifdef __cplusplus extern "C" { #endif /* File type values for the d_type member of struct dirent (kernel UAPI). */ #define DT_UNKNOWN 0 #define DT_FIFO 1 #define DT_CHR 2 #define DT_DIR 4 #define DT_BLK 6 #define DT_REG 8 #define DT_LNK 10 #define DT_SOCK 12 #define DT_WHT 14 /* * One directory entry. Layout equals the x86_64 struct linux_dirent64 * fields 0..18 verbatim; the name then follows at offset 19, stored in the * conventional 256-byte buffer. */ struct dirent { ino_t d_ino; /* 0: inode number */ off_t d_off; /* 8: offset of the next entry (seek cookie) */ unsigned short d_reclen; /* 16: length of the kernel record */ unsigned char d_type; /* 18: DT_* file type */ char d_name[256]; /* 19: NUL-terminated file name */ }; /* Pin the layout to the x86_64 kernel ABI. */ _Static_assert(sizeof(struct dirent) == 280, "struct dirent must match the x86_64 getdents64 layout"); _Static_assert(offsetof(struct dirent, d_off) == 8, "d_off must sit at offset 8"); _Static_assert(offsetof(struct dirent, d_type) == 18, "d_type must sit at offset 18"); _Static_assert(offsetof(struct dirent, d_name) == 19, "d_name must sit at offset 19"); /* * Opaque directory stream handle. The struct tag stays usable from the * internal layout header, which defines struct vlibc_DIR (see * src/dirent/dirent_impl.h). */ typedef struct vlibc_DIR DIR; /* * Open the directory named by path for reading and return a directory * stream positioned at its first entry, or NULL with errno set (a * non-directory path fails with ENOTDIR). The stream owns a descriptor * that closedir() releases. */ DIR * opendir(const char *path); /* * Like opendir(), but over the already-open descriptor fd, which must * refer to a directory (validated with fstat). On failure NULL is returned * with errno set and fd is left open and owned by the caller. */ DIR * fdopendir(int fd); /* * Return the next directory entry of dir, or NULL at the end of the * directory (errno untouched) or on error (errno set). The result points * at storage owned by dir and is valid until the next call to readdir, * rewinddir, seekdir, or closedir on the same stream. */ struct dirent * readdir(DIR *dir); /* * Reset dir to the beginning of the directory: the next readdir returns * the first entry again. Never fails. */ void rewinddir(DIR *dir); /* * Close dir, releasing its descriptor and storage. Return 0, or -1 with * errno set if the underlying close fails. */ int closedir(DIR *dir); /* * Reposition dir so the next readdir resumes at the location loc, which * must be a value previously returned by telldir (a getdents64 seek * cookie). Never fails. */ void seekdir(DIR *dir, long loc); /* * Return the current location of dir, for a later seekdir. The location is * the point after the entry most recently returned by readdir; it becomes * indeterminate after rewinddir or closedir. */ long telldir(DIR *dir); /* * Return the descriptor underlying dir. The descriptor stays owned by the * stream and remains valid until closedir. */ int dirfd(DIR *dir); #if VLIBC_LEVEL_GE(2) /* Level 2 (muslmimic): XSI and obsolescent. */ /* * Reentrant readdir: store the next entry in *buf and set *result to buf; * at the end of the directory *result is NULL. Returns 0 at end of * directory, an error number on failure (errno is not used for the error * report), and leaves errno unmodified on success. Obsolescent. */ int readdir_r(DIR *restrict dir, struct dirent *restrict buf, struct dirent **restrict result); /* * Read the whole directory named by path and store a malloc'd array of * malloc'd struct dirent copies in *res (both released with free; the * array is NULL-terminated with one extra NULL pointer). Only entries for * which sel is NULL or returns nonzero are kept; cmp, when non-NULL, sorts * the array (alphasort is the strcmp-on-name comparator). Returns the * number of entries, or -1 with errno set. XSI. */ int scandir(const char *path, struct dirent ***res, int (*sel)(const struct dirent *), int (*cmp)(const struct dirent **, const struct dirent **)); /* * Lexicographic comparator over the d_name fields of two struct dirent * pointers, for use as scandir's cmp argument. XSI. */ int alphasort(const struct dirent **a, const struct dirent **b); #endif /* VLIBC_LEVEL_GE(2) */ #ifdef __cplusplus } #endif #endif /* VLIBC_DIRENT_H */