1 #define _LARGEFILE64_SOURCE
12 #include <sys/types.h>
13 #include <sys/syscall.h>
15 /* Our own declaration taken from the kernel since glibc does not have it... */
16 struct linux_dirent64 {
19 unsigned short d_reclen;
24 #define MIN_NAME_LEN 8
25 #define MAX_NAME_LEN 70
29 static int ignore_error;
32 loff_t (*getpos)(void);
33 void (*setpos)(loff_t pos);
34 void (*getentry)(struct dirent *entry);
37 static off64_t libc_getpos(void)
42 static void libc_setpos(off64_t pos)
47 static void libc_getentry(struct dirent *entry)
55 fprintf(stderr, "Unexpected EOF while reading dir.\n");
63 memcpy(entry, ret, sizeof(struct dirent));
66 static off64_t kernel_getpos(void)
68 return lseek64(dfd, 0, SEEK_CUR);
71 static void kernel_setpos(off64_t pos)
73 lseek64(dfd, pos, SEEK_SET);
76 static void kernel_getentry(struct dirent *entry)
78 char dirbuf[NAME_MAX + 1 + sizeof(struct linux_dirent64)];
79 struct linux_dirent64 *lentry = (struct linux_dirent64 *)dirbuf;
82 ret = syscall(SYS_getdents64, dfd, lentry, sizeof(dirbuf));
90 fprintf(stderr, "Unexpected EOF while reading dir.\n");
93 entry->d_ino = lentry->d_ino;
94 entry->d_off = lentry->d_off;
95 entry->d_reclen = lentry->d_reclen;
96 entry->d_type = lentry->d_type;
97 strcpy(entry->d_name, lentry->d_name);
100 struct dir_ops libc_ops = {
101 .getpos = libc_getpos,
102 .setpos = libc_setpos,
103 .getentry = libc_getentry,
106 struct dir_ops kernel_ops = {
107 .getpos = kernel_getpos,
108 .setpos = kernel_setpos,
109 .getentry = kernel_getentry,
112 static void create_dir(char *dir, int count)
115 char namebuf[MAX_NAME_LEN];
118 dfd = open(dir, O_RDONLY | O_DIRECTORY);
120 perror("Cannot open dir");
123 for (i = 0; i < count; i++) {
124 len = random() % (MAX_NAME_LEN - MIN_NAME_LEN) + MIN_NAME_LEN;
125 for (j = 0; j < len; j++)
126 namebuf[j] = random() % 26 + 'a';
129 fd = openat(dfd, namebuf, O_RDWR | O_CREAT | O_EXCL, 0644);
131 if (errno == EEXIST) {
136 perror("File creation failed");
144 static void test(int count, struct dir_ops *ops)
149 loff_t dpos, maxpos = 0;
152 dbuf = calloc(count, sizeof(struct dirent));
153 pbuf = calloc(count, sizeof(loff_t));
154 if (!dbuf || !pbuf) {
155 fprintf(stderr, "Out of memory for buffers.\n");
159 for (i = 0; i < count; i++) {
160 pbuf[i] = ops->getpos();
161 if (pbuf[i] > maxpos)
163 ops->getentry(dbuf + i);
164 ops->setpos(dbuf[i].d_off);
167 for (i = 0; i < count; i++) {
168 pos = random() % count;
169 ops->setpos(pbuf[pos]);
170 ops->getentry(&entry);
171 if (dbuf[pos].d_ino != entry.d_ino ||
172 dbuf[pos].d_type != entry.d_type ||
173 strcmp(dbuf[pos].d_name, entry.d_name)) {
175 "Mismatch in dir entry %u at pos %llu\n", pos,
176 (unsigned long long)pbuf[pos]);
180 puts("Reading valid entries passed.");
183 for (i = 0; i < count; i++) {
184 dpos = random() % maxpos;
187 * We don't care about the result but the kernel should not
190 ops->getentry(&entry);
194 puts("Reading random positions passed.");
199 int main(int argc, char *argv[])
205 fprintf(stderr, "Usage: t_seekdir_3 <dir> <count> <seed>\n");
209 count = atoi(argv[2]);
210 seed = atol(argv[3]);
214 create_dir(argv[1], count);
216 puts("Testing readdir...");
217 dir = opendir(argv[1]);
219 perror("Cannot open dir");
222 test(count, &libc_ops);
226 puts("Testing getdents...");
227 dfd = open(argv[1], O_DIRECTORY | O_RDONLY);
229 perror("Cannot open dir");
232 test(count, &kernel_ops);
235 fprintf(stderr, "All tests passed\n");