xfs: test that reflink forces the log if mounted with wsync
[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 int
34 main(int argc, char *argv[])
35 {
36         int fd, nread;
37         char buf[BUF_SIZE];
38         struct linux_dirent64 *d;
39         int bpos, total, i;
40         off_t lret;
41         int retval = EXIT_SUCCESS;
42
43         fd = open(argv[1], O_RDONLY | O_DIRECTORY);
44         if (fd < 0) {
45                 perror("open");
46                 exit(EXIT_FAILURE);
47         }
48
49         total = 0;
50         for ( ; ; ) {
51                 nread = syscall(SYS_getdents64, fd, buf, BUF_SIZE);
52                 if (nread == -1) {
53                         perror("getdents");
54                         exit(EXIT_FAILURE);
55                 }
56
57                 if (nread == 0)
58                         break;
59
60                 for (bpos = 0; bpos < nread; total++) {
61                         d = (struct linux_dirent64 *) (buf + bpos);
62
63                         if (total >= HISTORY_LEN) {
64                                 fprintf(stderr, "too many files\n");
65                                 break;
66                         }
67
68                         for (i = 0; i < total; i++)
69                         {
70                                 if (d_off_history[i] == d->d_off) {
71                                         fprintf(stderr, "entries %d and %d have duplicate d_off %lld\n",
72                                                 i, total, (long long int)d->d_off);
73                                         retval = EXIT_FAILURE;
74                                 }
75                         }
76                         d_off_history[total] = d->d_off;
77                         d_ino_history[total] = d->d_ino;
78                         bpos += d->d_reclen;
79                 }
80         }
81
82         /* check if seek works correctly */
83         d = (struct linux_dirent64 *)buf;
84         for (i = total - 1; i >= 0; i--)
85         {
86                 lret = lseek(fd, i > 0 ? d_off_history[i - 1] : 0, SEEK_SET);
87                 if (lret == -1) {
88                         perror("lseek");
89                         exit(EXIT_FAILURE);
90                 }
91
92                 nread = syscall(SYS_getdents64, fd, buf, BUF_SIZE);
93                 if (nread == -1) {
94                         perror("getdents");
95                         exit(EXIT_FAILURE);
96                 }
97
98                 if (nread == 0) {
99                         fprintf(stderr, "getdents returned 0 on entry %d\n", i);
100                         retval = EXIT_FAILURE;
101                 }
102
103                 if (d->d_ino != d_ino_history[i]) {
104                         fprintf(stderr, "entry %d has inode %lld, expected %lld\n",
105                                 i, (long long int)d->d_ino, (long long int)d_ino_history[i]);
106                         retval = EXIT_FAILURE;
107                 }
108         }
109
110         close(fd);
111         exit(retval);
112 }