1665fa8deSThomas Weißschuh /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2665fa8deSThomas Weißschuh /*
3665fa8deSThomas Weißschuh * Directory access for NOLIBC
4665fa8deSThomas Weißschuh * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
5665fa8deSThomas Weißschuh */
6665fa8deSThomas Weißschuh
7*3785289fSThomas Weißschuh /* make sure to include all global symbols */
8*3785289fSThomas Weißschuh #include "nolibc.h"
9*3785289fSThomas Weißschuh
10665fa8deSThomas Weißschuh #ifndef _NOLIBC_DIRENT_H
11665fa8deSThomas Weißschuh #define _NOLIBC_DIRENT_H
12665fa8deSThomas Weißschuh
130e75768bSThomas Weißschuh #include "compiler.h"
14665fa8deSThomas Weißschuh #include "stdint.h"
15665fa8deSThomas Weißschuh #include "types.h"
16ecc091d9SThomas Weißschuh #include "fcntl.h"
17665fa8deSThomas Weißschuh
18665fa8deSThomas Weißschuh #include <linux/limits.h>
19665fa8deSThomas Weißschuh
20665fa8deSThomas Weißschuh struct dirent {
21665fa8deSThomas Weißschuh ino_t d_ino;
22665fa8deSThomas Weißschuh char d_name[NAME_MAX + 1];
23665fa8deSThomas Weißschuh };
24665fa8deSThomas Weißschuh
25665fa8deSThomas Weißschuh /* See comment of FILE in stdio.h */
26665fa8deSThomas Weißschuh typedef struct {
27665fa8deSThomas Weißschuh char dummy[1];
28665fa8deSThomas Weißschuh } DIR;
29665fa8deSThomas Weißschuh
30665fa8deSThomas Weißschuh static __attribute__((unused))
fdopendir(int fd)31665fa8deSThomas Weißschuh DIR *fdopendir(int fd)
32665fa8deSThomas Weißschuh {
33665fa8deSThomas Weißschuh if (fd < 0) {
34665fa8deSThomas Weißschuh SET_ERRNO(EBADF);
35665fa8deSThomas Weißschuh return NULL;
36665fa8deSThomas Weißschuh }
37665fa8deSThomas Weißschuh return (DIR *)(intptr_t)~fd;
38665fa8deSThomas Weißschuh }
39665fa8deSThomas Weißschuh
40665fa8deSThomas Weißschuh static __attribute__((unused))
opendir(const char * name)41665fa8deSThomas Weißschuh DIR *opendir(const char *name)
42665fa8deSThomas Weißschuh {
43665fa8deSThomas Weißschuh int fd;
44665fa8deSThomas Weißschuh
45665fa8deSThomas Weißschuh fd = open(name, O_RDONLY);
46665fa8deSThomas Weißschuh if (fd == -1)
47665fa8deSThomas Weißschuh return NULL;
48665fa8deSThomas Weißschuh return fdopendir(fd);
49665fa8deSThomas Weißschuh }
50665fa8deSThomas Weißschuh
51665fa8deSThomas Weißschuh static __attribute__((unused))
closedir(DIR * dirp)52665fa8deSThomas Weißschuh int closedir(DIR *dirp)
53665fa8deSThomas Weißschuh {
54665fa8deSThomas Weißschuh intptr_t i = (intptr_t)dirp;
55665fa8deSThomas Weißschuh
56665fa8deSThomas Weißschuh if (i >= 0) {
57665fa8deSThomas Weißschuh SET_ERRNO(EBADF);
58665fa8deSThomas Weißschuh return -1;
59665fa8deSThomas Weißschuh }
60665fa8deSThomas Weißschuh return close(~i);
61665fa8deSThomas Weißschuh }
62665fa8deSThomas Weißschuh
63665fa8deSThomas Weißschuh static __attribute__((unused))
readdir_r(DIR * dirp,struct dirent * entry,struct dirent ** result)64665fa8deSThomas Weißschuh int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
65665fa8deSThomas Weißschuh {
660e75768bSThomas Weißschuh char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1] __nolibc_aligned_as(struct linux_dirent64);
67665fa8deSThomas Weißschuh struct linux_dirent64 *ldir = (void *)buf;
68665fa8deSThomas Weißschuh intptr_t i = (intptr_t)dirp;
69665fa8deSThomas Weißschuh int fd, ret;
70665fa8deSThomas Weißschuh
71665fa8deSThomas Weißschuh if (i >= 0)
72665fa8deSThomas Weißschuh return EBADF;
73665fa8deSThomas Weißschuh
74665fa8deSThomas Weißschuh fd = ~i;
75665fa8deSThomas Weißschuh
76665fa8deSThomas Weißschuh ret = sys_getdents64(fd, ldir, sizeof(buf));
77665fa8deSThomas Weißschuh if (ret < 0)
78665fa8deSThomas Weißschuh return -ret;
79665fa8deSThomas Weißschuh if (ret == 0) {
80665fa8deSThomas Weißschuh *result = NULL;
81665fa8deSThomas Weißschuh return 0;
82665fa8deSThomas Weißschuh }
83665fa8deSThomas Weißschuh
84665fa8deSThomas Weißschuh /*
85665fa8deSThomas Weißschuh * getdents64() returns as many entries as fit the buffer.
86665fa8deSThomas Weißschuh * readdir() can only return one entry at a time.
87665fa8deSThomas Weißschuh * Make sure the non-returned ones are not skipped.
88665fa8deSThomas Weißschuh */
89665fa8deSThomas Weißschuh ret = lseek(fd, ldir->d_off, SEEK_SET);
90665fa8deSThomas Weißschuh if (ret == -1)
91665fa8deSThomas Weißschuh return errno;
92665fa8deSThomas Weißschuh
93665fa8deSThomas Weißschuh entry->d_ino = ldir->d_ino;
94665fa8deSThomas Weißschuh /* the destination should always be big enough */
95665fa8deSThomas Weißschuh strlcpy(entry->d_name, ldir->d_name, sizeof(entry->d_name));
96665fa8deSThomas Weißschuh *result = entry;
97665fa8deSThomas Weißschuh return 0;
98665fa8deSThomas Weißschuh }
99665fa8deSThomas Weißschuh
100665fa8deSThomas Weißschuh #endif /* _NOLIBC_DIRENT_H */
101