1
#include <apheleia/syscall.h>
2
#include <arch/sys.h>
3
#include <dirent.h>
4
#include <errno.h>
5
#include <fcntl.h>
6
#include <stdint.h>
7
#include <stdlib.h>
8
#include <unistd.h>
9
10
#define DIRENT_BUF_COUNT 32
11
12
struct DIR {
13
int fd;
14
size_t pos;
15
size_t count;
16
struct dirent entries[DIRENT_BUF_COUNT];
17
};
18
19
static ssize_t _getdents_raw(int fd, struct dirent *out, size_t len) {
20
if (!len) {
21
return 0;
22
}23
24
if (!out || len < sizeof(*out)) {
25
errno = EINVAL;
26
return -1;
27
}28
29
return (ssize_t)__SYSCALL_ERRNO(syscall3(SYS_GETDENTS, (uintptr_t)fd, (uintptr_t)out, (uintptr_t)len));
30
}31
32
#ifdef _APHELEIA_SOURCE
33
ssize_t getdents(int fd, struct dirent *out, size_t len) {
34
return _getdents_raw(fd, out, len);
35
}36
#endif37
38
DIR *opendir(const char *name) {
39
if (!name) {
40
errno = EINVAL;
41
return NULL;
42
}43
44
int fd = open(name, O_RDONLY | O_DIRECTORY);
45
if (fd < 0) {
46
return NULL;
47
}48
49
DIR *dirp = malloc(sizeof(*dirp));
50
if (!dirp) {
51
close(fd);
52
errno = ENOMEM;
53
return NULL;
54
}55
56
dirp->fd = fd;
57
dirp->pos = 0;
58
dirp->count = 0;
59
return dirp;
60
}61
62
struct dirent *readdir(DIR *dirp) {
63
if (!dirp) {
64
errno = EINVAL;
65
return NULL;
66
}67
68
if (dirp->pos >= dirp->count) {
69
ssize_t ret = _getdents_raw(dirp->fd, dirp->entries, sizeof(dirp->entries));
70
71
if (ret <= 0) {
72
return NULL;
73
}74
75
if ((size_t)ret % sizeof(dirp->entries[0])) {
76
errno = EIO;
77
return NULL;
78
}79
80
dirp->pos = 0;
81
dirp->count = (size_t)ret / sizeof(dirp->entries[0]);
82
}83
84
return &dirp->entries[dirp->pos++];
85
}86
87
int closedir(DIR *dirp) {
88
if (!dirp) {
89
errno = EINVAL;
90
return -1;
91
}92
93
int ret = close(dirp->fd);
94
free(dirp);
95
return ret;
96
}97
98
void rewinddir(DIR *dirp) {
99
if (!dirp) {
100
return;
101
}102
103
(void)lseek(dirp->fd, 0, SEEK_SET);
104
105
dirp->pos = 0;
106
dirp->count = 0;
107
}