src/t_dir_offset2: Add an option to limit of buffer size
[xfstests-dev.git] / src / t_dir_offset2.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2011 GraÅžvydas Ignotas
4  */
5
6 /*
7  * This test checks if no duplicate d_off values are returned and
8  * that these offsets are seekable to entry with the right inode.
9  */
10
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <stdint.h>
15 #include <stdlib.h>
16 #include <sys/stat.h>
17 #include <sys/syscall.h>
18
19 struct linux_dirent64 {
20         uint64_t        d_ino;
21         uint64_t        d_off;
22         unsigned short  d_reclen;
23         unsigned char   d_type;
24         char            d_name[0];
25 };
26
27 #define BUF_SIZE 4096
28 #define HISTORY_LEN 1024
29
30 static uint64_t d_off_history[HISTORY_LEN];
31 static uint64_t d_ino_history[HISTORY_LEN];
32
33 void usage()
34 {
35         fprintf(stderr, "usage: t_dir_offset2: <dir> [bufsize]\n");
36         exit(EXIT_FAILURE);
37 }
38
39 int main(int argc, char *argv[])
40 {
41         int fd;
42         char buf[BUF_SIZE];
43         int nread, bufsize = BUF_SIZE;
44         struct linux_dirent64 *d;
45         int bpos, total, i;
46         off_t lret;
47         int retval = EXIT_SUCCESS;
48
49         if (argc > 2) {
50                 bufsize = atoi(argv[2]);
51                 if (!bufsize)
52                         usage();
53                 if (bufsize > BUF_SIZE)
54                         bufsize = BUF_SIZE;
55         } else if (argc < 2) {
56                 usage();
57         }
58
59         fd = open(argv[1], O_RDONLY | O_DIRECTORY);
60         if (fd < 0) {
61                 perror("open");
62                 exit(EXIT_FAILURE);
63         }
64
65         total = 0;
66         for ( ; ; ) {
67                 nread = syscall(SYS_getdents64, fd, buf, bufsize);
68                 if (nread == -1) {
69                         perror("getdents");
70                         exit(EXIT_FAILURE);
71                 }
72
73                 if (nread == 0)
74                         break;
75
76                 for (bpos = 0; bpos < nread; total++) {
77                         d = (struct linux_dirent64 *) (buf + bpos);
78
79                         if (total >= HISTORY_LEN) {
80                                 fprintf(stderr, "too many files\n");
81                                 break;
82                         }
83
84                         for (i = 0; i < total; i++)
85                         {
86                                 if (d_off_history[i] == d->d_off) {
87                                         fprintf(stderr, "entries %d and %d have duplicate d_off %lld\n",
88                                                 i, total, (long long int)d->d_off);
89                                         retval = EXIT_FAILURE;
90                                 }
91                         }
92                         d_off_history[total] = d->d_off;
93                         d_ino_history[total] = d->d_ino;
94                         bpos += d->d_reclen;
95                 }
96         }
97
98         /* check if seek works correctly */
99         d = (struct linux_dirent64 *)buf;
100         for (i = total - 1; i >= 0; i--)
101         {
102                 lret = lseek(fd, i > 0 ? d_off_history[i - 1] : 0, SEEK_SET);
103                 if (lret == -1) {
104                         perror("lseek");
105                         exit(EXIT_FAILURE);
106                 }
107
108                 nread = syscall(SYS_getdents64, fd, buf, bufsize);
109                 if (nread == -1) {
110                         perror("getdents");
111                         exit(EXIT_FAILURE);
112                 }
113
114                 if (nread == 0) {
115                         fprintf(stderr, "getdents returned 0 on entry %d\n", i);
116                         retval = EXIT_FAILURE;
117                 }
118
119                 if (d->d_ino != d_ino_history[i]) {
120                         fprintf(stderr, "entry %d has inode %lld, expected %lld\n",
121                                 i, (long long int)d->d_ino, (long long int)d_ino_history[i]);
122                         retval = EXIT_FAILURE;
123                 }
124         }
125
126         close(fd);
127         exit(retval);
128 }