1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
2 /*
3 * Directory access for NOLIBC
4 * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net>
5 */
6
7 /* make sure to include all global symbols */
8 #include "nolibc.h"
9
10 #ifndef _NOLIBC_DIRENT_H
11 #define _NOLIBC_DIRENT_H
12
13 #include "compiler.h"
14 #include "stdint.h"
15 #include "types.h"
16 #include "fcntl.h"
17
18 #include <linux/limits.h>
19
20 struct dirent {
21 ino_t d_ino;
22 char d_name[NAME_MAX + 1];
23 };
24
25 /* See comment of FILE in stdio.h */
26 typedef struct {
27 char dummy[1];
28 } DIR;
29
30 static __attribute__((unused))
fdopendir(int fd)31 DIR *fdopendir(int fd)
32 {
33 if (fd < 0) {
34 SET_ERRNO(EBADF);
35 return NULL;
36 }
37 return (DIR *)(intptr_t)~fd;
38 }
39
40 static __attribute__((unused))
opendir(const char * name)41 DIR *opendir(const char *name)
42 {
43 int fd;
44
45 fd = open(name, O_RDONLY);
46 if (fd == -1)
47 return NULL;
48 return fdopendir(fd);
49 }
50
51 static __attribute__((unused))
closedir(DIR * dirp)52 int closedir(DIR *dirp)
53 {
54 intptr_t i = (intptr_t)dirp;
55
56 if (i >= 0) {
57 SET_ERRNO(EBADF);
58 return -1;
59 }
60 return close(~i);
61 }
62
63 static __attribute__((unused))
readdir_r(DIR * dirp,struct dirent * entry,struct dirent ** result)64 int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
65 {
66 char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1] __nolibc_aligned_as(struct linux_dirent64);
67 struct linux_dirent64 *ldir = (void *)buf;
68 intptr_t i = (intptr_t)dirp;
69 int fd, ret;
70
71 if (i >= 0)
72 return EBADF;
73
74 fd = ~i;
75
76 ret = sys_getdents64(fd, ldir, sizeof(buf));
77 if (ret < 0)
78 return -ret;
79 if (ret == 0) {
80 *result = NULL;
81 return 0;
82 }
83
84 /*
85 * getdents64() returns as many entries as fit the buffer.
86 * readdir() can only return one entry at a time.
87 * Make sure the non-returned ones are not skipped.
88 */
89 ret = lseek(fd, ldir->d_off, SEEK_SET);
90 if (ret == -1)
91 return errno;
92
93 entry->d_ino = ldir->d_ino;
94 /* the destination should always be big enough */
95 strlcpy(entry->d_name, ldir->d_name, sizeof(entry->d_name));
96 *result = entry;
97 return 0;
98 }
99
100 #endif /* _NOLIBC_DIRENT_H */
101