xref: /linux/tools/lib/api/io_dir.h (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
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