| 1 |
|
| 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
|
| 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;
|
| 46 | off64_t d_off;
|
| 47 | unsigned short d_reclen;
|
| 48 | unsigned char d_type;
|
| 49 | char d_name[NAME_MAX + 1];
|
| 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, 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
|