xref: /linux/tools/include/nolibc/dirent.h (revision 015a99fa76650e7d6efa3e36f20c0f5b346fe9ce)
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