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 if (fd < 0) { 34 SET_ERRNO(EBADF); 35 return NULL; 36 } 37 return (DIR *)(intptr_t)~fd; 38 } 39 40 static __attribute__((unused)) 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)) 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)) 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