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