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