git.cappig.dev / apheleiaOS.git master

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
#endif
37
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
}