Files

180 lines
5.5 KiB
C

#ifndef VLIBC_DIRENT_H
#define VLIBC_DIRENT_H
/*
* vlibc — <dirent.h>.
*
* 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 <vlibc/features.h>
#include <stddef.h>
#include <sys/types.h>
#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 */