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)) 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)) 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)) 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)) 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