1d118b08fSIan Rogers /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ 2d118b08fSIan Rogers /* 3d118b08fSIan Rogers * Lightweight directory reading library. 4d118b08fSIan Rogers */ 5d118b08fSIan Rogers #ifndef __API_IO_DIR__ 6d118b08fSIan Rogers #define __API_IO_DIR__ 7d118b08fSIan Rogers 8d118b08fSIan Rogers #include <dirent.h> 9d118b08fSIan Rogers #include <fcntl.h> 10d118b08fSIan Rogers #include <stdlib.h> 11d118b08fSIan Rogers #include <unistd.h> 12d118b08fSIan Rogers #include <sys/stat.h> 13d118b08fSIan Rogers #include <sys/syscall.h> 14*0c9f3a85SArnaldo Carvalho de Melo #include <linux/limits.h> 15d118b08fSIan Rogers 16d118b08fSIan Rogers #if !defined(SYS_getdents64) 17d118b08fSIan Rogers #if defined(__x86_64__) || defined(__arm__) 18d118b08fSIan Rogers #define SYS_getdents64 217 19d118b08fSIan Rogers #elif defined(__i386__) || defined(__s390x__) || defined(__sh__) 20d118b08fSIan Rogers #define SYS_getdents64 220 21d118b08fSIan Rogers #elif defined(__alpha__) 22d118b08fSIan Rogers #define SYS_getdents64 377 23d118b08fSIan Rogers #elif defined(__mips__) 24d118b08fSIan Rogers #define SYS_getdents64 308 25d118b08fSIan Rogers #elif defined(__powerpc64__) || defined(__powerpc__) 26d118b08fSIan Rogers #define SYS_getdents64 202 27d118b08fSIan Rogers #elif defined(__sparc64__) || defined(__sparc__) 28d118b08fSIan Rogers #define SYS_getdents64 154 29d118b08fSIan Rogers #elif defined(__xtensa__) 30d118b08fSIan Rogers #define SYS_getdents64 60 31d118b08fSIan Rogers #else 32d118b08fSIan Rogers #define SYS_getdents64 61 33d118b08fSIan Rogers #endif 34d118b08fSIan Rogers #endif /* !defined(SYS_getdents64) */ 35d118b08fSIan Rogers 36d118b08fSIan Rogers static inline ssize_t perf_getdents64(int fd, void *dirp, size_t count) 37d118b08fSIan Rogers { 38d118b08fSIan Rogers #ifdef MEMORY_SANITIZER 39d118b08fSIan Rogers memset(dirp, 0, count); 40d118b08fSIan Rogers #endif 41d118b08fSIan Rogers return syscall(SYS_getdents64, fd, dirp, count); 42d118b08fSIan Rogers } 43d118b08fSIan Rogers 44d118b08fSIan Rogers struct io_dirent64 { 45d118b08fSIan Rogers ino64_t d_ino; /* 64-bit inode number */ 46d118b08fSIan Rogers off64_t d_off; /* 64-bit offset to next structure */ 47d118b08fSIan Rogers unsigned short d_reclen; /* Size of this dirent */ 48d118b08fSIan Rogers unsigned char d_type; /* File type */ 49d118b08fSIan Rogers char d_name[NAME_MAX + 1]; /* Filename (null-terminated) */ 50d118b08fSIan Rogers }; 51d118b08fSIan Rogers 52d118b08fSIan Rogers struct io_dir { 53d118b08fSIan Rogers int dirfd; 54d118b08fSIan Rogers ssize_t available_bytes; 55d118b08fSIan Rogers struct io_dirent64 *next; 56d118b08fSIan Rogers struct io_dirent64 buff[4]; 57d118b08fSIan Rogers }; 58d118b08fSIan Rogers 59d118b08fSIan Rogers static inline void io_dir__init(struct io_dir *iod, int dirfd) 60d118b08fSIan Rogers { 61d118b08fSIan Rogers iod->dirfd = dirfd; 62d118b08fSIan Rogers iod->available_bytes = 0; 63d118b08fSIan Rogers } 64d118b08fSIan Rogers 65d118b08fSIan Rogers static inline void io_dir__rewinddir(struct io_dir *iod) 66d118b08fSIan Rogers { 67d118b08fSIan Rogers lseek(iod->dirfd, 0, SEEK_SET); 68d118b08fSIan Rogers iod->available_bytes = 0; 69d118b08fSIan Rogers } 70d118b08fSIan Rogers 71d118b08fSIan Rogers static inline struct io_dirent64 *io_dir__readdir(struct io_dir *iod) 72d118b08fSIan Rogers { 73d118b08fSIan Rogers struct io_dirent64 *entry; 74d118b08fSIan Rogers 75d118b08fSIan Rogers if (iod->available_bytes <= 0) { 76d118b08fSIan Rogers ssize_t rc = perf_getdents64(iod->dirfd, iod->buff, sizeof(iod->buff)); 77d118b08fSIan Rogers 78d118b08fSIan Rogers if (rc <= 0) 79d118b08fSIan Rogers return NULL; 80d118b08fSIan Rogers iod->available_bytes = rc; 81d118b08fSIan Rogers iod->next = iod->buff; 82d118b08fSIan Rogers } 83d118b08fSIan Rogers entry = iod->next; 84d118b08fSIan Rogers iod->next = (struct io_dirent64 *)((char *)entry + entry->d_reclen); 85d118b08fSIan Rogers iod->available_bytes -= entry->d_reclen; 86d118b08fSIan Rogers return entry; 87d118b08fSIan Rogers } 88d118b08fSIan Rogers 89d118b08fSIan Rogers static inline bool io_dir__is_dir(const struct io_dir *iod, struct io_dirent64 *dent) 90d118b08fSIan Rogers { 91d118b08fSIan Rogers if (dent->d_type == DT_UNKNOWN) { 92d118b08fSIan Rogers struct stat st; 93d118b08fSIan Rogers 94d118b08fSIan Rogers if (fstatat(iod->dirfd, dent->d_name, &st, /*flags=*/0)) 95d118b08fSIan Rogers return false; 96d118b08fSIan Rogers 97d118b08fSIan Rogers if (S_ISDIR(st.st_mode)) { 98d118b08fSIan Rogers dent->d_type = DT_DIR; 99d118b08fSIan Rogers return true; 100d118b08fSIan Rogers } 101d118b08fSIan Rogers } 102d118b08fSIan Rogers return dent->d_type == DT_DIR; 103d118b08fSIan Rogers } 104d118b08fSIan Rogers 105d118b08fSIan Rogers #endif /* __API_IO_DIR__ */ 106