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