xref: /linux/tools/include/nolibc/dirent.h (revision bb29b957eaaa15be33243550d9ee576c2d601669)
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))
31 DIR *fdopendir(int fd)
32 {
33 	struct stat buf;
34 	int ret;
35 
36 	if (fd < 0) {
37 		SET_ERRNO(EBADF);
38 		return NULL;
39 	}
40 
41 	ret = fstat(fd, &buf);
42 	if (ret < 0)
43 		return NULL;
44 
45 	if (!S_ISDIR(buf.st_mode)) {
46 		SET_ERRNO(ENOTDIR);
47 		return NULL;
48 	}
49 
50 	return (DIR *)(intptr_t)~fd;
51 }
52 
53 static __attribute__((unused))
54 DIR *opendir(const char *name)
55 {
56 	int fd;
57 
58 	fd = open(name, O_RDONLY | O_DIRECTORY);
59 	if (fd == -1)
60 		return NULL;
61 
62 	return (DIR *)(intptr_t)~fd;
63 }
64 
65 static __attribute__((unused))
66 int closedir(DIR *dirp)
67 {
68 	intptr_t i = (intptr_t)dirp;
69 
70 	if (i >= 0) {
71 		SET_ERRNO(EBADF);
72 		return -1;
73 	}
74 	return close(~i);
75 }
76 
77 static __attribute__((unused))
78 int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
79 {
80 	char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1] __nolibc_aligned_as(struct linux_dirent64);
81 	struct linux_dirent64 *ldir = (void *)buf;
82 	intptr_t i = (intptr_t)dirp;
83 	int fd, ret;
84 	off_t off;
85 
86 	if (i >= 0)
87 		return EBADF;
88 
89 	fd = ~i;
90 
91 	ret = _sys_getdents64(fd, ldir, sizeof(buf));
92 	if (ret < 0)
93 		return -ret;
94 	if (ret == 0) {
95 		*result = NULL;
96 		return 0;
97 	}
98 
99 	/*
100 	 * getdents64() returns as many entries as fit the buffer.
101 	 * readdir() can only return one entry at a time.
102 	 * Make sure the non-returned ones are not skipped.
103 	 */
104 	off = _sys_lseek(fd, ldir->d_off, SEEK_SET);
105 	if (off < 0)
106 		return -off;
107 
108 	entry->d_ino = ldir->d_ino;
109 	/* the destination should always be big enough */
110 	strlcpy(entry->d_name, ldir->d_name, sizeof(entry->d_name));
111 	*result = entry;
112 	return 0;
113 }
114 
115 #endif /* _NOLIBC_DIRENT_H */
116