| /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ | |
| /* | |
| * Directory access for NOLIBC | |
| * Copyright (C) 2025 Thomas Weißschuh <linux@weissschuh.net> | |
| */ | |
| /* make sure to include all global symbols */ | |
| #include "nolibc.h" | |
| #ifndef _NOLIBC_DIRENT_H | |
| #define _NOLIBC_DIRENT_H | |
| #include "compiler.h" | |
| #include "stdint.h" | |
| #include "types.h" | |
| #include "fcntl.h" | |
| #include <linux/limits.h> | |
| struct dirent { | |
| ino_t d_ino; | |
| char d_name[NAME_MAX + 1]; | |
| }; | |
| /* See comment of FILE in stdio.h */ | |
| typedef struct { | |
| char dummy[1]; | |
| } DIR; | |
| static __attribute__((unused)) | |
| DIR *fdopendir(int fd) | |
| { | |
| if (fd < 0) { | |
| SET_ERRNO(EBADF); | |
| return NULL; | |
| } | |
| return (DIR *)(intptr_t)~fd; | |
| } | |
| static __attribute__((unused)) | |
| DIR *opendir(const char *name) | |
| { | |
| int fd; | |
| fd = open(name, O_RDONLY); | |
| if (fd == -1) | |
| return NULL; | |
| return fdopendir(fd); | |
| } | |
| static __attribute__((unused)) | |
| int closedir(DIR *dirp) | |
| { | |
| intptr_t i = (intptr_t)dirp; | |
| if (i >= 0) { | |
| SET_ERRNO(EBADF); | |
| return -1; | |
| } | |
| return close(~i); | |
| } | |
| static __attribute__((unused)) | |
| int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) | |
| { | |
| char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1] __nolibc_aligned_as(struct linux_dirent64); | |
| struct linux_dirent64 *ldir = (void *)buf; | |
| intptr_t i = (intptr_t)dirp; | |
| int fd, ret; | |
| if (i >= 0) | |
| return EBADF; | |
| fd = ~i; | |
| ret = _sys_getdents64(fd, ldir, sizeof(buf)); | |
| if (ret < 0) | |
| return -ret; | |
| if (ret == 0) { | |
| *result = NULL; | |
| return 0; | |
| } | |
| /* | |
| * getdents64() returns as many entries as fit the buffer. | |
| * readdir() can only return one entry at a time. | |
| * Make sure the non-returned ones are not skipped. | |
| */ | |
| ret = _sys_lseek(fd, ldir->d_off, SEEK_SET); | |
| if (ret < 0) | |
| return -ret; | |
| entry->d_ino = ldir->d_ino; | |
| /* the destination should always be big enough */ | |
| strlcpy(entry->d_name, ldir->d_name, sizeof(entry->d_name)); | |
| *result = entry; | |
| return 0; | |
| } | |
| #endif /* _NOLIBC_DIRENT_H */ |