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