feat(dirent): directory iteration
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
#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 */
|
||||
Reference in New Issue
Block a user