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