at master 2.6 kB view raw
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 36static 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 44struct 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 52struct io_dir { 53 int dirfd; 54 ssize_t available_bytes; 55 struct io_dirent64 *next; 56 struct io_dirent64 buff[4]; 57}; 58 59static inline void io_dir__init(struct io_dir *iod, int dirfd) 60{ 61 iod->dirfd = dirfd; 62 iod->available_bytes = 0; 63} 64 65static inline void io_dir__rewinddir(struct io_dir *iod) 66{ 67 lseek(iod->dirfd, 0, SEEK_SET); 68 iod->available_bytes = 0; 69} 70 71static 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 89static 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__ */